[React]state, props, useState

DY·2022년 8월 2일
0

React

목록 보기
4/9

State

  • 컴포넌트의 사용중 컴포넌트 내부에서 동적으로 변할 수 있는 값

State 사용

import React, { useState } from "react";
import "./styles.css";

function CheckboxExample() {
  const [isChecked, setIsChecked] = useState(false);

  const handleChecked = (event) => {
    setIsChecked(event.target.checked);
  };
  return (
    <div className="App">
      <input type="checkbox" checked={isChecked} onChange={handleChecked} />
      <span>{isChecked ? "Checked!!" : "Unchecked"}</span>
    </div>
  );
}

export default CheckboxExample;

State hook, useState

useState 사용법

  • React에서 state를 다루는 방법 중 하나
  1. useState를 import
import { useState } from "react";
  1. useState 를 컴포넌트 안에서 호출한다.
    useState 를 호출한다는 것은 "state" 라는 변수를 선언하는 것과 같으며, 이 변수의 이름은 아무 이름으로 지어도 된다.
  const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);  state의 초깃값

  const [isChecked, setIsChecked] = useState(false);

  //또는
  const stateHookArray = useState(false);
  const isChecked = stateHookArray[0];
  const setIsChecked = stateHookArray[1];

state 변수에 저장된 값을 사용하려면 isChecked변수에 할당된 값을 활용한다.

  • isChecked : state를 저장하는 변수
  • setIsChecked : state, isChecked 를 변경하는 함수
  • useState : state hook
  • false : state의 초깃값으로 주는 값(isCehcked에는 false가 들어간다)

주의점

  • React 컴포넌트는 state가 변경되면 리렌더링된다.
    위에서 setIsChecked함수가 실행되고 isChecked변수를 해당 컴포넌트함수에 넘겨 다시 랜더링시킨다. 즉 속해있는 해당 함수를 다시 실행시킨다는 의미이다.
  • state는 상태 변경 함수 호출로 변경해야 리렌더링이 되므로 강제로 변경시키면 안된다. 따라서 let이 아닌 const로 선언된것이고 강제로 함수내에서 해당 함수를 호출한다고하면 hook문제로 오류가 난다.
  • 상태변경함수의 역할은? : state값 변경

자주사용하는 state

  • 다크모드설정일때 로그인되어있을때 등 상태값을 bool형으로 나타낼때 많이 사용한다. 업데이트 되어 재랜더링이 필요할 때 등 매우 자주사용한다.
import React, { useState } from "react";
import "./styles.css";

function App() {
  const [showPopup, setShowPopup] = useState(false);

  const togglePopup = () => {
    // Pop up 의 open/close 상태에 따라
    // 현재 state 가 업데이트 되도록 함수를 완성하세요.
    if (showPopup) {
      setShowPopup(false);
    } else {
      setShowPopup(true);
    }
  };

  return (
    <div className="App">
      <h1>Fix me to open Pop Up</h1>
      {/* 버튼을 클릭했을 때 Pop up 의 open/close 가 작동하도록
          button tag를 완성하세요. */}
      <button className="open" onClick={togglePopup}>
        Open me
      </button>
      {showPopup ? (
        <div className="popup">
          <div className="popup_inner">
            <h2>Success!</h2>
            <button className="close" onClick={togglePopup}>
              Close me
            </button>
          </div>
        </div>
      ) : null}
    </div>
  );
}

export default App;

상태끌어올리기

React는 하향식(top-down)이자 단방향 데이터흐름방식을 따른다. 이때 하위 컴포넌트에서 일나는 이벤트가 상위 컴포넌트에 영향을 주는 경우가 존재하는데 마치 역방향 데이터 흐름처럼 보인다.
React에서는 이러한 상황에서는 아래와같이 해결한다.

1. 상위 컴포넌트에 정의된 state함수를 하위 컴포넌트에 props로 전달.
2. 하위 컴포넌트에서 이 콜백함수를 실행

/* 부모 컴포넌트 */
const Top = () =>{
//1. State선언
const [deleteMessage, setdeleteMessage] = useState("Bye");	

//2. 전달할 콜백함수 선언
const handleMessage = (delivered) => {					
   setdeleteMessage(delivered);
}
	console.log(deleteMessage)		// 처음 Bye출력, 클릭후 Hi 출력
  return (
	<div>
		<Bottom Message={deleteMessage} onClick_delete={handleMessage}/>
	</div>
  );
};

/* 자식 컴포넌트 */

// 매개변수는 {Message, onClick_delete}각각 deleteMessage, handleMessage가 들어가 있음.
//({})가 아닌 ()으로 받으면 객체자체(props)로 받는거고 ({})는 구조분해할당과 같은 역할

const Bottom = ({ Message, onClick_delete }) => {
  const handleMessageClick = ()=>{
    onClick_delete("Hi");	//Hi대신 Bottom에서 만든 변수나 값을 전달할수 있음.
  }
  return (
  	<button onClick={handleMessageClick}>삭제</button>
  );
};

Props

  • 외부에서 전달받은 값 즉 외부에서 변화해서 들어온 값
  • React 컴포넌트는 JavsCript의 함수와 클래스로 props를 argument처럼 전달받아 사용한다. 따라서 최초 렌더링 될 때 화면에 출력하고자하는 데이터를 담은 초깃값으로 사용할 수 있다.
  • 어떠한 타입도 넣어 전달할수 있도록 객체 형태이다.
  • 함수내부에서 변하지 말아야하므로 read-only. 읽기전용 값이다.

Props 사용

1.하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의한다.
2. props를 이용하여 정의된 값과 속성을 전달한다.
3. 전달받은 props를 렌더링한다.

function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child attribute={value} />
      <Child text ={"Hello Child"} />
    </div>
  );
};

function Child(props) {
  return (
    <div className="child">
    	<p>{props.text}</p>
    	<p>{props.attribute}</p>
    </div>
  );
};
  • props에 key, value형식으로 들어가므로 전달시 key value 형식으로 전달하면 된다.
function Parent() {
  return (
    <div className="parent">
        <h1>I'm the parent</h1>
        <Child>I'm the eldest child</Child>
    </div>
  );
};

function Child(props) {
  return (
    <div className="child">
        <p>{props.children}</p>
    </div>
  );
};
  • Child 태그사이에 값을 넣어 전달하고 props.children으로 받는 방법도 있다.

useState 주의사항

1.

  • 아래의 코드가 있다. countbtn을 세번누르고 handlebtn을 누른뒤 countbtn을 여러번 눌렀을때 3초뒤 alert되는 값은 무엇일까?
function Counter() {
  const [count, setCount] = useState(0);

  function handleAlertClick() {
    setTimeout(() => {
      alert('You clicked on: ' + count);
    }, 3000);
  }
  return (
    <div>
      <p>You clicked {count} times</p>
      <button className = "countbtn"onClick={() => setCount(count + 1)}>
        countbtn
      </button>
      <button className = "handlebtn" onClick={handleAlertClick}>
        handlebtn
      </button>
    </div>
  );
}

비슷한예로 아래와같은 현상도 있다.

import React, { useState } from "react"

function App() {

  const [num, setNum] = useState(1)

  async function plus() {
    setNum(num + 1)
    setNum(num + 1)
    setNum(num + 1)
  }

  async function minus() {
    setNum(num - 1)
  }

  return (
    <div className="App">
      <h1>{num}</h1>
      <button onClick={plus}>PLUS</button>
      <button onClick={minus}>MINUS</button>
    </div>
  );
}

export default App;
  • PLUS를 실행해도 1만 증가된 모습을 볼수 있다. 아까말한것처럼 현재의 lexical scope를 기억하고 실행해서이다. React는 16ms동안 실행한 동일한 setState를 일괄처리를 하므로 최종적으로 마지막의 setState만 실행이된다.

  • 해결방안은 setNum(num => num + 1)으로 바꾸면된다.

  • 여러번 전달받는 함수들은 큐에 저장되어 순서대로 실행된다. 따라서 큐에서 먼저 수행된 함수의 결과로 반영된 state값이 다음 수행할 함수의 인자로 들어가게 되므로, 항상 최신의 state를 유지하게 된다

https://garve32.tistory.com/39

2. 재랜더링시 주의점

import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

let t = [
  {
    "itemId": 1,
    "quantity": 1
  },
  {
    "itemId": 5,
    "quantity": 7
  },
]
let tt = [{
  "itemId": 1,
  "quantity": 1
}]

function App() {
  const [temp, setTemp] = useState(t);
  const [temp2, setTemp2] = useState(temp.map(el => el.itemId));
  // 위에 두개는 최초 랜더링될때만 실행됨.

  console.log(temp);
  console.log(temp2);

  return (
    <div className="App">
      <button onClick={() => { setTemp(tt) }}>TEST</button>
    </div>
  );
}

export default App;

후기

state prop를 이용하여 간단한 게시판 만들기를 해봤다.
개념학습부터 활용까지 2일이 걸렸지만 배운게 많았다.
각각에 대한 개념은 이 블로그에 따로 정리를 했고 SPA를 구현하기에 매우 적합한 문법인것 같다.
기능별로 컴포넌트화를 시키고 top-down방식으로 개발을 하니 확실히 유지보수에 편할것 같고 개발하는 데 있어서도 분업과 협업에 있어서 매우 적합하다고 생각이 들었다.

간단게시판구현

소스 주소
https://github.com/kkdy21/fe-sprint-react-twittler-state-props.git

profile
프론트엔드 개발자가 되기 위해 공부중입니다. 블로그는 공부한 내용을 올리고 있습니다.

0개의 댓글