Web Dev/3. React 관련

useEffect 내에서 state를 변화하고, 내부에서 함수를 호출했을때, 왜 변화한 state가 보이지 않는가?

hYhY1234 2021. 5. 19. 16:06
728x90

https://stackoverflow.com/questions/53024496/state-not-updating-when-using-react-state-hook-within-setinterval

 

State not updating when using React state hook within setInterval

I'm trying out the new React Hooks and have a Clock component with a counter which is supposed to increase every second. However, the value does not increase beyond one. function Clock() { ...

stackoverflow.com

 

Intermediate React 세미나를 듣다가 정리하고 싶은 내용이 생겨서 짤막하게 메모해 본다. 

import { useState, useRef } from "react";

const RefComponent = () => {
  const [stateNumber, setStateNumber] = useState(0);
  const numRef = useRef(0);

  function incrementAndDelayLogging() {
    setStateNumber(stateNumber + 1);
    numRef.current++;
    setTimeout(
      // stateNumber은 이전값을 가지고있다. closure
      () => alert(`state: ${stateNumber} | ref: ${numRef.current}`),
      1000
    );
  }

  return (
    <div>
      <h1>useRef Example</h1>
      <button onClick={incrementAndDelayLogging}>delay logging</button>
      <h4>state: {stateNumber}</h4>
      <h4>ref: {numRef.current}</h4>
    </div>
  );
};

export default RefComponent;

// from https://codesandbox.io/s/strange-mirzakhani-0xhvx?file=/src/Ref.js:0-648

위의 코드를 보면 useEffect내에서 state를 업데이트 하더라도, setTimeout에서 콜백함수가 실행될때는 변화한 state가 아니라, 이 콜백함수가 등록될때의 state가 보여진다. 

 

여기서 delay logging을 실행하면

 

rerendering이 발생하면서 컴포넌트의 state, ref는 변경되지만, 이전 사이클에서 등록한 setTimeout내의 콜백함수(클로저) 이전 사이클의 state값을 가지고 있기때문에, alert에는 변경전의 state가 보인다. 

 

 

그냥 종종 헷갈려서 한번 정리를 해보았다. 위의 stackoverflow글을 보면 정말 설명을 잘해두었다.