[React Hooks 총정리] useLayoutEffect

혜빈·2024년 7월 24일
0

REACT 보충개념

목록 보기
39/48

useLayoutEffect

  • 자주 사용하지는 않지만 알아두면 유리함
  • useEffect와 비슷하고 사용하는 방법도 동일함
  • 첫 번째 인자로 effect라는 콜백함수를 전달받고, 두 번째 인자로 의존성 배열을 전달받음
  • useEffect, useLayoutEffect 모두 컴포넌트가 처음 렌더링 될 때, 의존성 배열에 있는 값이 업데이트 될때마다 effect가 실행됨

- useEffect, useLayoutEffect의 차이점은?
-> effect가 실행되는 시점

useEffect

  • useEffect는 일반적으로 업데이트된 컴포넌트가 화면에 그려지고 effect가 실행됨

useLayoutEffect

  • useLayoutEffect는 effect가 실행되고 업데이트된 컴포넌트가 화면에 그려짐
  • 사용자에게 보여지는 UI 변화를 더 정교하게 다룰 수 있음
  • 예를들어 컴포넌트가 화면에 보여지기 이전에 effct안에서 어디에 어떤식으로 보여줄지에 대한 계산을 미리 완료하고 나서 업데이트된 화면을 사용자에게 보여줄 수 있음

실전 코드 실습

  • 코드상으로 useEffect가 useLayoutEffect보다 먼저 오는데도 불구하고 useLayoutEffect가 먼저 실행됨

  • useEffect는 컴포넌트가 화면에 그려지고 난 이후에 실행이 됨

  • 첫 번째 인자인 effect는 비동기적으로 실행됨 (다른 작업을 블로킹 하지 않고 적절한 때에 실행이 됨)


블로킹(blocking)

  • 컴퓨터 프로그래밍에서 특정 작업이 완료될 때까지 다른 작업을 중단시키는 것

  • 주로 동기적(synchronous) 작업에서 발생하고, 해당 작업이 완료될 때까지 프로그램의 실행이 멈추게 됨

  • 예를 들면, 파일을 읽는 동기적 함수가 있다면 파일을 모두 읽을 때까지 프로그램의 실행을 멈추게 되고 파일 읽기가 완료된 후에 다른 작업을 수행할 수 있음

  • 비동기적(asunchronous) 작업은 블로킹을 피함

  • 호출된 후 즉시 제어권을 반환하며, 작업이 완료되면 콜백함수나 promise를 통해 결과를 처리함

  • 이는 프로그램이 다른 작업을 계속 수행할 수 있게 해줌


  • useLayoutEffect의 effect는 컴포넌트가 화면에 그려지기 이전에 실행이 됨

  • 위 코드의 실행 순서를 보면 useLayouteffect가 실행이 되고, 화면이 그려지고, useEffect가 실행이 됨

  • update 버턴을 클릭하면 업데이트 된 컴포넌트가 화면에 그려지기 이전에 useLayoutEffect가 먼저 실행이 되고, 컴포넌트가 화면에 그려지고, useEffect가 실행됨

  • useLayoutEffect는 effect가 동기적으로 실행됨

  • 해당 작업이 실행되는 동안 다른 작업은 실행되지 못하게 블로킹함
    (useLayoutEffect가 실행되는 동안은 화면이 업데이트 되지 않음)
    - 따라서, useLayoutEffect를 과하게 사용하거나 이 안에서 무거운 작업을 한다면 APP의 성능을 저하시킬 수 있음

useLayoutEffect를 사용하기 좋은 상황

  • 컴포넌트를 화면에 배치하기 전에 레이아웃이나 스크롤같은 UI적인 계산을 해야 할 때 사용하면 좋음

실제 코드 실습

  • 컴포넌트가 렌더링되면 getNumbers라는 API를 호출해서 가져온 숫자를 파란 박스 안에 보여주는 기능 구현
import { useEffect, useRef, useState } from "react";

// 외부에서 데이터를 가져오는 API라고 가정
function getNumbers() {
  return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
}

function UseLayOutEffectHook2() {
  const [numbers, setNumbers] = useState([]);
  const ref = useRef(null);

  useEffect(() => {
    const nums = getNumbers();
    setNumbers(nums);
  }, []);

  // 페이지가 로딩되자마자 제일 마지막 숫자까지 보이도록 스크롤이 맨 아래까지 내려가도록 작업
  // useEffect를 통해 getNumbers로부터 받아온 nums가 setNumbers를 통해 numbers라는 state 안에 들어가면
  // 자동으로 스크롤을 내려주는 코드 작성하기

  // numbers가 아직 로딩되지 않았을 때는 스크롤을 내려주지 않기
  useEffect(() => {
    if (numbers.length === 0) {
      return;
    }

    ref.current.scrollTop = ref.current.scrollHeight;
  }, [numbers]);

  return (
    <div
      ref={ref}
      style={{
        height: "300px",
        border: "1px solid blue",
        overflow: "scroll",
      }}
    >
      {numbers.map((number, idx) => (
        <p key={idx}>{number}</p>
      ))}
    </div>
  );
}

export default UseLayOutEffectHook2;

  • 페이지가 로딩되자마자 제일 마지막 숫자까지 보이도록 스크롤이 맨 아래까지 내려가도록 잘 동작함
  • 그런데 만약 App이 훨씬 복잡하고 많은일을 하거나, App을 실행하는 기기가 느리다면 자동으로 스크롤이 되는 과정에서 딜레이가 발생할 수 있음

- 딜레이 없이 정확한 시점에 UI 변화를 보여주고 싶다면 useEffect가 아니라 useLayoutEffect를 사용하자

  • useLayoutEffect를 사용했더니 딜레이 없이 스크롤이 잘 되는 것을 볼 수 있음
  • 업데이트된 컴포넌트가 화면에 그려지기 이전에 실행되기 때문임
  • useLayoutEffect는 동기적으로 실행되기 때문에 effect가 실행되는동안 화면이 업데이트 되는 것을 블로킹함
    - 화면이 딜레이 되는것이 화면이 업데이트 되기 전에 실행될것을 보장받을 수 있기 때문에 딜레이가 없음
    (UI가 이미 다 계산된 후에 화면이 그려지기 때문임)

- 이처럼 사용자에게 보여지는 UI 변화를 더 정교하게 다뤄야 될 때는 useLayoutEffect를 사용하면 됨

주의할점

  • useLayoutEffect는 effect가 모두 완료될때까지 화면업데이트가 발생하지 못하도록 블로킹하기 때문에 불필요하게 남용하면 프로그램 성능에 큰 무리가 갈 수 있음

  • 만약 useEffect와 useLayoutEffect중 고민하는 경우,
    대부분의 경우 useEffect를 사용하는 것이 더 좋은 판단일 때가 많음

profile
최강 개발자를 꿈꾸는 병아리

0개의 댓글