React의 함수형 컴포넌트를 이용해 개발하다 보면 useEffect
와 useLayoutEffect
를 마주치는 일이 많다. 이 두 가지 Hooks를 잘 알지 못하고 코드를 실행시킬 경우 큰 차이점을 느끼기 어려울 수 있다. 그러나 위 두 Hooks는 분명히 다르며, 적절히 사용할 수 있는 방법도 다르다.
위 Hooks에 대해 이해하기 위해서는 render, paint를 포함하는 리액트의 lifecycle에 대한 이해가 있으면 좋다.
렌더링이란 컴포넌트의 UI를 구성하기 위해 render tree를 생성하는 과정이다. 이 과정에서 React는 Virtual DOM
을 생성하여 변경된 DOM tree를 휴리스틱 알고리즘으로 비교하여 렌더링을 최적화한다.
페인팅이란 화면에 최종적으로 생성된 DOM tree를 그려주는 작업이다.
useEffect
가 컴포넌트에 포함되어 있을 때 실행되는 과정은 아래와 같다.
1. (리렌더링일 경우) state 및 props 변경
2. 렌더링
3. 페인팅
4. useEffect() // 비동기적 실행
즉, useEffect
는 렌더링과 페인팅이 모두 끝난 후 실행된다. 이미 화면이 그려졌기 때문에 useEffect 내부에 DOM에 변경을 주는 코드가 있을 경우, 유저는 flickering 현상을 겪을 수 있다.
useLayoutEffect
가 컴포넌트에 포함되어 있을 때 실행되는 과정은 아래와 같다.
1. (리렌더링일 경우) state 및 props 변경
2. 렌더링
3. useLayoutEffect() // 동기적 실행
4. 페인팅
useLayoutEffect
는 화면에 페이지가 그려지기 전 동기적으로 실행되게 된다. flickering 현상이 일어나지는 않지만 useLayoutEffect 내부에 오랜 시간이 걸리는 코드가 있을 경우, 유저가 첫 화면을 볼 때까지 오랜 시간이 걸릴 수 있다.
비동기 요청 등 오래 걸리는 작업이 있을 경우 useEffect
를 사용하는 것이 좋다. 유저 입장에서 flickering 현상을 겪게 되더라도 첫 화면을 보기까지 오래 걸리지 않을 가능성이 높기 때문이다.
다만, 내부 코드가 오랜 시간이 걸리지 않는게 분명하고, 첫 화면부터 정확한 데이터를 보여줘야만 한다면 useLayoutEffect
를 사용하는게 적절할 수 있다.
[stack overflow] Calling render vs painting the DOM?
[React] useEffect 와 useLayoutEffect 의 차이는 무엇일까?
React Hooks — useState, useEffect, useRef, useMemo (TicTacToe Game)