React Hooks의 암묵적인 규칙

The unspoken rules of React hooks를 읽고 요약한 글입니다.

useEffect의 종속성 배열에는 콜백 내에서 참조되는 모든 변수가 포함되어야 한다는 규칙이 있다. 규칙 위반을 방지하기 위해 eslint의 react-hooks/exhaustive-dpeps 규칙을 설정하기도 하는데, 종속성 배열에서 누락된 참조가 있다면 알려주는 식이다.

하지만, 이 규칙에도 예외가 있는데 일부 "안정적인 것으로 알려져 있는" 값은 종속성 배열에 추가하지 않아도 된다는 내용이다. eslint 규칙 구현에서도 그 일부를 확인할 수 있다.

Some are known to be stable based on Hook calls.

const [state, setState] = useState() / React.useState()
              ^^^ true for this reference
const [state, dispatch] = useReducer() / React.useReducer()
              ^^^ true for this reference
const [state, dispatch] = useActionState() / React.useActionState()
              ^^^ true for this reference
const ref = useRef()
      ^^^ true for this reference
const onStuff = useEffectEvent(() => {})
      ^^^ true for this reference

False for everything else.

리액트 공식 문서도 이 내용을 언급하고 있는데 요약하자면,

  • useRef 훅의 ref객체는 종속성 배열에 포함시키지 않아도 된다.
  • 모든 렌더링에서 항상 동일한 객체를 얻을 수 있음이 보장된다.
  • useState의 set 함수도 stable identity를 갖기 때문에 종속성 배열에 포함시키지 않아도 된다.
  • 단, 부모 컴포넌트에서 전달된 경우 항상 동일한 참조를 전달하는지 알기 어렵기 때문에 종속성 배열에 포함시켜야 한다.

회사 프로젝트에서도 해당 eslint 규칙을 사용하기 때문에 어느 정도 알고 있던 내용이지만 깊게 생각해 본 적은 없었다. 근데 어떤 값이 안정이고 그렇지 않은지 어떻게 판별할 수 있는걸까? 실제로 어떤 라이브러리에서 넘기는 값은 종속성 배열의 예외로 취급되기도 하고 아니기도 한데, 출처에서는 이러한 내용들이 명확하지 않다고 지적하고 있다. 리액트 공식 문서에서는 다음과 같이 언급할 뿐이고 더 자세한 내용은 찾지 못했다.

Omitting always-stable dependencies only works when the linter can “see” that the object is stable.

Backlinks 1