Skip to main content

Command Palette

Search for a command to run...

TIL: React의 의존성 관리

Published
2 min readView as Markdown
D
I created SWC, an open-source compiler project, and previously worked at Deno and Vercel. These days, I spend a lot of time building Labor0, along with Watchtower and The AI Platform at Zephyr Cloud IO.

재밌는 질문을 받았다. 그리고 답변을 고민하다가 React가 의존성을 관리하는 방식에 대해 알게 되어서 글로 남긴다.

질문

질문은 아래 컴포넌트를 렌더링하고 버튼을 2번째 눌렀을 때 왜 저 함수가 다시 호출되면서 console.log가 실행되는지 모르겠다는 내용이었다.

import { useEffect, useState } from "react";

function UseEffectTest() {
  // state only for rerender
  const [foo, setFoo] = useState(true);

  console.log("outside of useEffect, but inside of component", "foo: ", foo);

  useEffect(() => {
    console.log("RE-RENDERED", "foo: ", foo);
  });

  return (
    <div>
      {console.log("---inside JSX---", "foo: ", foo)}
      <button
        onClick={() => {
          setFoo(false);
        }}
      >
        rerender me!
      </button>
    </div>
  );
}

export default UseEffectTest;

나도 모르던 내용이라 처음엔

스트릭트 모드 때문 아닌가?

했다. 그런데 프로덕션 빌드에서도, next@12react@17로 테스트해봐도 똑같더라. 그리고 버튼을 더 눌러도 다시 렌더링이 되지 않았다.

고민하다가 깨달았다. 이건 React API의 한계다.

답변

React 함수 컴포넌트는 의존성 배열이라는 걸 사용한다. 그리고 fooboolean 타입을 가진 변수인데, 의존성 배열에 들어갈 수 있다. 변화 내용을 추적하거나 의존성 그래프를 그리기 위한 정보가 아예 없는, boolean 같은 값들이 의존성 배열에 직접 들어간다는 것이다. use*는 의존성 그래프 없이 다시 실행할지 여부를 결정해야한다. 이럴 때 쓸 수 있는 방법이 foofalse로 놓고 컴포넌트를 다시 실행해보는 것이다. 실행하면서 의존성 배열에 다른 값이 들어오는지 확인하면, foofalse로 바뀌었을 때 다시 실행돼야하는 코드가 있는지 알 수 있다. 이후에 버튼을 다시 클릭해도 로그가 찍히지 않는 건 이전 실행의 결과로 foofalse로 바뀌어도 다시 실행될 필요가 없다는 걸 알았기 때문일 것이다.


오랜만에 답변하면서도 배울 게 있는 질문이었다.

More from this blog