우리가 자주 사용하는 useEffect() 훅 말고도 react는 useLayoutEffect() 라는 훅을 제공한다. 이 훅은 useEffect()와 동일하게 컴포넌트의 마운트 이후 실행된다는 점은 비슷하다. 차이점은 useEffect()는 비동기적으로 실행되고, useLayoutEffect() 훅은 동기적으로 실행된다는 점이다.
useEffect()는 화면이 다 그려진 이후 (= paint와 layout 과정이 이루어진 후) 비동기적으로 실행된다. useLayoutEffect()는 렌더링 후 layout과 paint과정이 일어나기 전 동기적으로 실행된다.즉, useLayoutEffect() 훅은 다른 콜백 함수들의 실행이 종료되어야 실행된다는 뜻이고, 깜빡임 현상이 일어나지 않는 효과가 있다. 반면 useEffect()는 종료 여부와 상관없이 콜백 함수들을 기다리지 않는다는 뜻이고, 때에 따라서 깜빡임 현상이 발생할 수 있다.
react 공식문서에서는 아래와 같은 useLayoutEffect() 훅의 특징 때문에 useEffect() 훅의 사용을 더욱 권장하고 있다.
실행되는 동안 브라우저는 컴포넌트의 렌더링을 중단한다. 따라서 useLayoutEffect() 내부에서 오랫동안 실행되는 작업을 수행하면 브라우저의 응답성이 떨어질 수 있다.
useEffect() 훅은 비동기적으로 실행되기에 브라우저의 응답성에 영향을 주지 않는다.
useLayoutEffect()의 특징은 렌더링 작업이 끝난 직후 동기적으로 호출된다는 특징을 갖고 있다. 이 특징을 응용해야하는 로직이 필요할 때, 이 훅을 사용하면 좋다. 예를 들어, DOM 요소의 크기나 위치와 같은 값을 측정하거나 조작하는 작업이 필요할 때 사용하면 좋다.
import React, { useLayoutEffect, useRef } from 'react';
function Component() {
const ref = useRef<HTMLDivElement | null>(null);
useLayoutEffect(() => {
// DOM 요소의 크기를 측정하거나 조작하는 작업
const width = ref!.current!.offsetWidth;
const height = ref!.current!.offsetHeight;
// ... 작업 수행 ...
}, []);
return <div ref={ref}>Some content</div>;
}
혹은, 계산된 state 값을 화면에 표출해야 하는 경우에도 사용된다.
import React, { useState, useLayoutEffect } from 'react';
const MyComponent = () => {
const [value, setValue] = useState(0);
// 컴포넌트가 렌더링 이후에 실행되는 효과
useLayoutEffect(() => {
setCalculatedValue(newValue);
}, []); // 두 번째 매개변수로 빈 배열을 전달하여 최초 한 번만 실행되도록 합니다.
return <div>{calculatedValue}</div>;
}
하지만
useEffect()의 깜빡임 현상은 0.25배속으로 봐도 확인이 힘들 정도로 미미하며, 성능상으로도useLayoutEffect()보다 효율적이기에, 특별한 경우가 아니라면useEffect()를 사용하는 것을 권장한다.