프론트엔드/React

useState 의 setState는 비동적으로 동작

journey-dev 2024. 5. 6. 21:34

✅ 동일한 setState 함수를 ”setState(value) 형태로” 여러번 호출한다면?

  • 맨 마지막 업데이트된 state로만 반영됨.
  • value = 6 , 12 , 18… 이 아닌, 3, 6, 9가 됨.
const InputPrac = () => {
  const [value, setValue] = useState(0); // value = 3 6 9 ...
  const addNum = (e) => {
    setValue(value + 1);
    setValue(value + 2);
    setValue(value + 3);
  };

  return (
    <>
      <p>{value}</p>
      <button onClick={addNum}>클릭</button>
    </>
  );
};

export default InputPrac;

설명

리액트는 setState가 호출되면 state가 변경되는 것으로 인지하는데,
한번의 이벤트 발생시 연속으로 같은 setstate가 실행되면,state가 업데이트되어 연속으로 리렌더링 될 것이다.

이는 비효율적이고 비용도 많이 든다.

때문에 이벤트 발생시 실행되는 콜백함수 내에서의 state의 "가장 마지막 갱신 내용"으로 state를 "한번만" 업데이트 시키게 된다.

 

✅ 동일한 setstate함수를 “콜백함수 형식으로” 여러번 호출한다면?

위의 내용과 달리 , setstate함수를 "호출할 때 마다" state가 연속으로 갱신되고, 그 값을 인자로 받아서 사용할 수 있다.

이 방식을 통해 갱신된 state값을 사용할 수 있다.

const InputPrac = () => {
  const [value, setValue] = useState(0);  // value = 6 12 18 ...
  const addNum = (e) => {
    setValue((prev) => prev + 1); // prev = 0 // updated value = 1
    setValue((prev) => prev + 2); // prev = 1 // updated value = 3
    setValue((prev) => prev + 3); // prev = 3 // updated value = 6
  };

  return (
    <>
      <p>{value}</p>
      <button onClick={addNum}>클릭</button>
    </>
  );
};

설명

  • setstate를 콜백함수 형식으로 쓴다면, setstate의 인자로 업데이트 된 state값을 받아올 수 있다.
  • 하지만 setstate함수를 통해 갱신된 state가 DOM에 리렌더 되는 때는
    addNum 콜백함수 본문이 다 끝나고 나서 반영되기 때문에, 최종 업데이트된 값(6, 12 , 18으로 보여지게 되는 것이다.

 

✅ 결론 - useState 의 setState는 비동기적으로 동작한다

 


 

 

<문제의 코드>

const InputPrac = () => {
  const [value, setValue] = useState(0); 
// value : 0 , 6 , 12 , 18

  const [valueMul, setValueMul] = useState(100); 
// valueMul : 100(value = 0) , 106(value = 6) , 118(value = 12)

  const addNum = (e) => {
    setValue((prev) => prev + 1); // 1
    setValue((prev) => prev + 2); // 3
    setValue((prev) => prev + 3); // 6, 12, 18
    setValueMul((prev) => value + prev); // 100(value = 0) 106(value = 6) 118(value = 12)
  };

  return (
    <>
      <p>{value}</p>
      <p>value가 바로 반영이 안됨 => {valueMul}</p>
      <button onClick={addNum}>클릭</button>
    </>
  );
};

문제

  • setValue가 최종적으로 6으로 업데이트 되니까 그 값을 활용하여 setValueMul함수를 실행하려고 했음.
  • 그러나 valueMul(100) + value(6) = 106을 기대했는데, 100이 나오고, 다음번 addNum실행시 value(6)이 참조되어 106이 나옴. 이런식으로 하나씩 밀려서 나옴.

이유 - 클로져의 원리 때문에

  1. setValueMul 함수가 실행될 땐, InputPrac함수의 스코프가 이미 끝나있다.
  2. 때문에 setValueMul함수 안에서 받는 prev인자는 InputPrac함수의 스코프가 있을당시의 값인 0을 참조하게 되는것이다. (클로져)

 

 

참조자료

1. https://stackoverflow.com/questions/42038590/when-to-use-react-setstate-callback\

2. https://bamtory29.tistory.com/entry/React-useState%EC%9D%98-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%A0%81-%EB%8F%99%EC%9E%91

3. https://velog.io/@kym123123/%EB%B9%84%EB%8F%99%EA%B8%B0%EB%A1%9C-%EB%8F%99%EC%9E%91%ED%95%98%EB%8A%94-react%EC%9D%98-setState%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC