사실 과제테스트를 끝내고 회고를 하다보니, 아래의 예시는 useEffect, useLayoutEffect 둘 다 쓸 필요가 없는 상황이었다... ㅎㅎ
하지만 이를 위해 useLayoutEffect에 대해 알아봤던게 아까워서 일단 글을 써본다!
---
엘리스 회사 과제테스트를 보다가 아래와 같은 UI에서 가격 필터링을 구현해야했다.
해당 가격 필터링은 URL search params로 저장하며 새로고침해도 해당 필터링 값이 남아있어야했다.
이를 구현은 했지만, 새로고침하면 처음에는 "무료" 필터링이 선택되지 않은 상태였다가 선택된 상태로 바뀌면서 화면 렌더링이 두번 되는 이른바 "깜빡"이는 현상이 발생했다.

`react-router-dom`의 `useSearchParams` 훅을 선언했고, `setSearchParams`로 선택한 필터링 조건을 URL params로 업데이트 시켜주었다.
하지만 `setSearchParams`는 `useState`의 setter와 달리 화면을 리렌더링 시키진 않았다.
따라서 `useEffect`로 화면을 리렌더링시켰는데, 이 과정에서 위와 같이 깜빡이는 현상이 발생한 것 같았다.
이전에 React의 hooks API를 보면서 useEffect와 비슷한 기능을 하는 useLayoutEffect가 있는데, 이는 useEffect의 setup로직을 브라우저가 화면을 다시 그리기 전에 실행시킨다는 차이점을 가지고 있어 한번 써보았다.
아래와 같이 필터링 조건 부분이 깜빡이지 않고 첫 렌더링부터 초기값을 잘 갖고 있는 것을 볼 수 있다.

useEffect와 useLayoutEffect의 차이점
- useEffect
useEffect의 setup(콜백함수에 들어가는 로직)이 실행되는 시점은 DOM 업데이트가 완료되고, 브라우저가 화면을 그린 후에 실행이 된다. 해당 로직은 비동기적으로 작업을 수행하기에 브라우저가 화면을 먼저 그릴 수 있는 것이다.
따라서 브라우저가 렌더링에 필요한 작업을 끝낸 후 실행되므로, 화면의 첫 렌더링에 영향을 미치지 않는다.
이는 useLayoutEffect에 비해 사용자에게 빠르게 뭐라도 화면에 보여주므로 사용자경험(UX)에 좋을 수도 있다고 한다.
- useLayoutEffect
이 훅이 생긴 이유는 DOM 업데이트 직후, 화면에 컴포넌트들이 그려지기 전, 동기적으로 작업을 수행한다.
따라서 브라우저가 렌더링을 하는 작업을 useLayoutEffect의 setup 작업이 완료될 때까지 멈춘다.
이는 브라우저 렌더링 성능에 영향을 주고, 해당 작업이 완료될 때까지 화면에는 UI가 그려지지 않는다. 사용자 경험에 안 좋을 수도 있다.
따라서 React 공식문서에서는 `useEffect`를 기본으로 선택하고, `useLayoutEffect`는 꼭 필요한 경우에만 쓰라고 한다.
예를 들어, 레이아웃을 측정하거나 DOM 조작을 화면 표시 전에 정확히 이루어져야하는 등이다.
공식문서에서는 아래와 같이 도움말의 위치를 계산하는 예시를 보여준다.


조금 더 들어가보자..
우테코 동료 크루인 러기가 'useLayoutEffect이 어떻게 렌더링 타이밍을 알고 실행되는 것인가'에 대한 말을 했다.
나도 궁금해서 찾아보았다.
이를 이해하기 위해선 '브라우저의 렌더링 사이클'과 'React의 렌더링 과정'에 대해 알아야할 것 같다.
브라우저의 렌더링 사이클
1. HTML 파싱
2. CSS 파싱
<JS 실행>
3. 렌더 트리 생성
4. Layout (Reflow) 단계
5. Paint 단계
6. Composite 단계
React의 렌더링 과정
1. React의 render
컴포넌트를 렌더링하며 가상 DOM을 업데이트한다.
2. React의 commit
가상 DOM의 변화를 실제 DOM에 반영한다.
-> 이때 `useLayoutEffect`가 실제 DOM 업데이트 직후, 브라우저가 Paint 단계로 넘어가기 직전에 실행된다.
따라서 브라우저의 성능 문제가 발생할 수 있는 것이다.
3. 브라우저 Paint
DOM이 브라우저의 화면에 그려진다.
-> `useEffect`는 브라우저의 화면이 그려진 후 실행된다.
그래서 useLayoutEffect는 Paint 단계 전에 실행된다.
브라우저의 Layout 단계와 Paint 단계 이전에 실행된다.
따라서 DOM 업데이트 이후, 정확한 레이아웃을 계산 하거나, DOM이 화면에 그려지기 전 '동기적'으로 추가적인 DOM을 조작할 때 사용된다.
재밌었던 것은 `requestAnimationFrame`과 비슷한 타이밍에 실행된다는 자료도 있었고, useEffect가 때때로 paint 전에 실행된다는 아티클도 있었다.
'React' 카테고리의 다른 글
Tanstack-Query 캐싱이 왜 필요하지? (gcTime, staleTime) (1) | 2024.12.12 |
---|---|
|| (논리 OR 연산자) 와 ?? (널 병합 연산자)는 언제 뭘 써야할까? (2) | 2024.12.02 |
프론트엔드에서 post 중복 요청을 어떻게 막을까? (with tanstack-query, playwright) (0) | 2024.11.27 |