리액트 – useState 유의할 점

콜백함수 형태로 state 업데이트

버튼을 한번 클릭했을때 state의 count가 5씩 증가하는 콜백함수를 만들어보자.

  const [count, setCount] = useState(0);
  const onIncrease = () => {
    setCount(count + 1); //1
    setCount(count + 1); //1
    setCount(count + 1); //1
    setCount(count + 1); //1
    setCount(count + 1); //1
  };

위와 같이 처리하면 콜백함수 실행시 5씩 증가할까 ? 아니다.

자바스크립트 클로저와 관련이 있는데, 콜백함수가 전달될때 현재상태를 스냅샷을 한다. 스냅샷이 될때 외부변수 count 값이 0으로 저장된다.

그래서 아무리 많이 setCount를 호출해도 count가 0으로 고정되어있으므로 1이다.

setState 를 정의하는 방법에는 한번에 값을 정의하는 방법과 이전 상태값을 인자로 전달하는 콜백함수 형태로 전달하는 방법이 있다.

  const [count, setCount] = useState(0);
  const onIncrease = () => {
    setCount((prev) => prev + 1);
    setCount((prev) => prev + 1);
    setCount((prev) => prev + 1);
    setCount((prev) => prev + 1);
    setCount((prev) => prev + 1);
  };

이렇게 이전 상태값을 인자로 받아서 업데이트를 하면 된다.


여러 상태값 합치기

여러 컴포넌트들의 상태값을 합쳐서 표현해주려면 어떻게 해야할까?

부모컴포넌트에 setState 함수를 정의한 후 그걸 props로 자식 컴포넌트들에 전달한다.

export default function AppCounter() {
  const [count, setCount] = useState(0);
  const handleClick = () => setCount((prev) => prev + 1);
  return (
    <div className="container">
      <div className="banner">
        Total Count : {count} {count > 10 ? "😍" : "🥰"}
      </div>
      <div className="counters">
        <Counter total={count} onClick={handleClick} />
        <Counter total={count} onClick={handleClick} />
      </div>
    </div>
  );
}
export default function Counter({ total, onClick }) {
  const [count, setCount] = useState(0);
  const onIncrease = () => {
    setCount((prev) => prev + 1);
  };
  return (
    <div className="counter">
      <span className="number">{count}</span>{" "}
      <span className="total">/{total}</span>
      <button
        className="button"
        onClick={() => {
          onIncrease();
          onClick();
        }}
      >
        Add +
      </button>
    </div>
  );
}

그래서 위와 같이 하위 컴포넌트들의 state도 변경하면서 전체 count 역시 증가시킬 수 있다.

정리

state를 업데이트하는 함수는 기존에 스냅샷된 외부값에 의존하기 보다는, callback 함수 형태로 set 하는것이 안전하다.

여러 state를 종합할 필요가 있을때는 부모 컴포넌트에 setState를 선언 후 자식 컴포넌트에 props로 전달한다.