[TIL] React - useEffect vs useLayoutEffect

jeongjwon·2023년 12월 5일
0

이론

목록 보기
16/19

useLayoutEffect vs useEffect

useLayoutEffect is a version of useEffect that fires before the browser repaints the screen.
useLayoutEffect(setup, dependencies?)

useLayoutEffect 공식문서 에 따르면 useLayoutEffect 는브라우저가 화면을 다시 그리기 전에 시작되는 useEffect 버전이라고 한다.


useEffect is a React Hook that lets you synchronize a component with an external system.
useEffect(setup, dependencies?)

useLayoutEffect 공식문서 에는 useEffect는 구성 요소를 외부 시스템과 동기화할 수 있는 React Hook이라고 한다.

보는 것과 같이 둘의 훅의 형태는 동일하다.
그렇다면 무슨 차이가 있을까?







useEffect

공식문서 중

the broswer paint the updated screen first before running your Effect.
the browser may repaint the screen before processing the state updates inside you Effect.

useEffect 를 사용하면 이펙트가 실행 전에 먼저 페인트 작업을 수행한다. 즉, DOM의 레이아웃 배치와 페인트가 끝난 후에 이펙트 함수가 호출한다. 따라서 상태값이 이펙트에 의존하면 사용자에게는 약간 불편하게 느껴질 수도 있다.



import { useEffect, useState } from "react";

function Introduce() {
  const [age, setAge] = useState(0);
  const [name, setName] = useState("");

  useEffect(() => {
    setAge(25);
    setName("찬민");
  }, []);

  return (
    <>
      <div className="App">{`그의 이름은 ${name} 이며, 나이는 ${age}살 입니다.`}</div>
    </>
  );
}

export default Introduce;

위는 useEffect 를 사용한 코드이다. 실행 순서를 살펴보면
1. <div>그의 이름은 __이며, 나이는 0살 입니다.</div> 를 페인트
2. 이펙트 내부의 setNumber, setAge 호출
3. 재렌더링 수행 -> <div>그의 이름은 찬민이며, 나이는 25살 입니다.</div>

간단한 로직의 구성이라 잘 보이지는 않지만, 로직이 복잡해짐에 따라 DOM 구조도 깊어지면 확연히 눈에 띌 정도로 렌더링 시간이 증가하게 될 것이다.

공식문서의 예를 보면 더 잘 느낄 수 있을 것이다. 속도가 느린 장치일 수록 더 잘 느끼는데, 일부러 버그를 재현하기 위해 인위적인 지연을 추가해놓았다.
툴팁을 hover 하면 초기 위치가 잠시 표시되고 수정된 위치 이전로 옮겨지는 것을 볼 수 있다.
이는 useEffect 가 내부 상태가 업데이트 전에 모두 페인트 한다는 것을 증명할 수 있다.






useLayoutEffect

import { useLayoutEffect, useState } from "react";

function Introduce() {
  const [age, setAge] = useState(0);
  const [name, setName] = useState("");

  useLayoutEffect(() => {
    setAge(25);
    setName("찬민");
  }, []);

  return (
    <>
      <div className="App">{`그의 이름은 ${name} 이며, 나이는 ${age}살 입니다.`}</div>
    </>
  );
}

export default Introduce;

이번에는 useLayoutEffect 로 변경한 코드인데, 실행순서는 다음과 같다.

  1. 레이아웃 이펙트 내부의 setNumber, setAge 호출
  2. <div>그의 이름은 찬민이며, 나이는 25살 입니다.</div>

별반 다를바 없어 보이긴 한다.

공식문서의 예를 살펴보면 확연히 툴팁 박스가 깜빡이는 정도가 없다.
다시 말해, useLayoutEffect는 화면에 그리기 전에 상태가 업데이트되는 것을 보장한다.









결론

hook-flow 프로젝트의 hook flow diagram 을 보고 잘 느껴질 수도 있다.



  • useEffect 의 이펙트는 DOM 이 화면에 그려진 후 호출된다.
  • useLayoutEffect 의 이펙트는 DOM 이 화면에 그려지기 전에 호출된다.
  • 따라서 렌더링할 상태가 이펙트 내에서 초기화되어야 할 경우, 사용자 경험을 위해 useLayoutEffect 를 활용하는 것이 더 좋다.






마무리

예전 코드스테이츠의 메인 프로젝트의 타팀의 피드백을 듣는 시간을 가진 적이 있다. 이때 타팀원분이 useLayoutEffect 훅을 사용해보는 것을 추천해주셨다. 조금은 늦었지만, 업데이트 전과 후의 페이트 작업의 차이로 차이점을 확실히 알게 되었다.
메인 프로젝트의 소감에서 사용해보지 않았던 hook 이나 package 를 활용해보고 싶다고 했었다. 지금 블로깅을 하면서 사용해보고 싶었던, 그리고 잘 활용되고, 리소스를 효율적으로 쓸 수 있는 hook 이나 package 를 공부해보고자 한다.







참조 : https://react.dev/reference/react/useLayoutEffect#measuring-layout-before-the-browser-repaints-the-screen

0개의 댓글