리액트의 각 Hook이 언제 실행되는지를 이해하고 적용하는 것은 컴포넌트의 동작을 예측 가능하게 만드는 데 중요합니다. 예를 들어, useEffect
Hook이 렌더링 후에 비동기적으로 실행된다는 사실을 이해하면, 이 Hook 내부에서 상태를 변경하는 작업 시 발생할 수 있는 잠재적인 문제를 미리 방지할 수 있습니다.
그렇다면 useState
, useMemo
, useEffect
, useLayoutEffect
는 어떤 순서로 실행될까요?
그 순서는 아래와 같습니다
1. useState, useMemo
2. useLayoutEffect
3. useEffect
React 는 function 컴포넌트의 rerender 시에도 useState 를 이용한 local state 을 보존할 수 있게 합니다.
이것은 이전 state 와 새로운 state 를 merge 하지 않는 점 외에는, class 컴포넌트의 this.setState 과 유사합니다.
또한, this.setState 와는 다르게 state 가 object 이어야 할 필요가 없습니다.
useState는 변수하나 만들 때 사용하고, useMemo는 []
안의 값이 변경될 때 다시 코드를 실행하고 싶은 경우에 사용합니다.
useState
와 useMemo
, 이 두 Hook은 컴포넌트 렌더링 단계에서 호출됩니다. 렌더링 단계에서 호출되어야, Linked List로 구현된 Hook의 특성을 활용해 호출 순서를 기억하고, 상태와 관련 메모이제이션된 값을 올바르게 유지할 수 있습니다.
useLayoutEffect
는 렌더링이 일어난 직후, 즉 DOM 업데이트가 일어나고 브라우저가 '레이아웃 단계'를 수행하기 전에 동기적으로 실행됩니다. 이는 Critical Rendering Path에서 'Paint' 단계 이전에 실행되는 것을 의미합니다. 동기적으로 실행되므로, 사용이 과도하면 UI 블로킹을 일으킬 수 있습니다.
useLayoutEffect 실행 👉 state 호출 👉 HTML 영역을 화면에 그림
마지막으로, useEffect
는 브라우저가 Paint 단계 완료한 이후에 비동기적으로 실행됩니다. 화면이 완전히 그려진 후에 비동기적으로 실행되므로, useEffect 내의 작업이 렌더링에 영향을 주지 않습니다.
*Paint 단계 : 렌더링이 완료되고 React가 DOM을 업데이트한 후 브라우저는 화면을 다시 그립니다. 이 단계를 “브라우저 렌더링”이라고 하지만 이 문서의 나머지 부분에서 혼동을 피하고자 “페인팅”이라고 부름
HTML 영역을 화면에 그림 👉 useEffect 실행 👉 state 호출 👉 HTML을 재렌더링
useLayoutEffect는 동기적으로 실행되므로 state 값을 가져올 때 오래걸린다면 사용자가 빈 화면을 마주하는 시간이 길어질 수 있다는 단점이 있습니다. useLayoutEffect가 무조건 좋은 방법이 아니라는 것!
따라서 기본적으로 useEffect를 사용하되, state에 따라 화면이 다르게 보여야 하는 경우라면 화면의 깜빡임을 방지하기 위해 useLayoutEffect를 사용하는 게 바람직합니다.
출처