- useLayoutEffect는 성능을 저하시킬 수 있기 때문에, 가급적 useEffect를 사용하는 것을 권장한다.
- useLayoutEffect는 브라우저가 화면을 다시 채우기 전에 실행되는 버전의 useEffect이다.
- 즉, 브라우저가 화면을 다시 그리기 전에 useLayoutEffect를 호출하여 레이아웃을 측정한다.
Mesuring layout before the browser repaints the screen(브라우저에서 화면을 다시 그리기 전 레이아웃 측정하기)
- 예를들어 마우스오버 시 요소 옆에 툴팁을 표시하는 기능이 있다고 가정했을 때, 공간이 충분하면 툴팁이 요소 위에 표시되지만, 공간이 충분하지 않으면 아래에 표시되게 하고 싶을 때, useLayoutEffect를 사용할 수 있다.
- 이 경우 1. 툴팁을 원하는 위치에 렌더링 2. 높이를 측정하고 툴팁을 배치할 위치 결정 3. 올바른 위치에 툴팁을 다시 렌더링 과정을 거쳐야 한다.
- 이때, 위와 같은 작업을 브라우저가 화면을 다시 그리기 전에 이루어지게 하고 싶다면, 브라우저가 화면을 다시 그리기 전에 useLayoutEffect를 호출하여 레이아웃 측정을 수행할 수 있다.
function Tooltip() {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0); // You don't know real height yet
// 아직 실제 height 값을 모릅니다.
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height); // Re-render now that you know the real height
// 실제 높이를 알았으니 이제 리렌더링 합니다.
}, []);
// ...use tooltipHeight in the rendering logic below...
// ...아래에 작성될 렌더링 로직에 tooltipHeight를 사용합니다...
}
* useLayoutEffect VS useEffect
- useLayoutEffect는 브라우저가 다시 그리는 것을 차단하지만, useEffect는 브라우저를 차단하지 않는다.
useLayoutEffect가 서버에서 아무것도 수행하지 않습니다.
- useLayoutEffect의 목적은 컴포넌트가 렌더링에 레이아웃 정보를 사용하도록 하는 것이다.
- 사용자 또는 프레임워크가 서버 렌더링을 사용하는 경우, React 앱은 초기 렌더링을 위해 서버의 HTML로 렌더링되고 이를 통해 JavaScript 코드가 로드되기 전에 초기 HTML을 표기할 수 있다.
- 이때, 서버에는 레이아웃 정보가 없기 때문에, 위의 예제의 경우 초기 서버 HTML의 일부로 Tooltip을 렌더링하려고 하면 이를 확인할 수 없다.
- 일반적으로 레이아웃 정보에 의존하는 컴포넌트는 서버에서 렌더링할 필요가 없다. 위의 예제의 경우에도 초기 렌더링 중에 Tooltip을 표시하는 것은 의미가 없을 수 있다.(Tooltip은 클라이언트의 상호작용에 의해 촉발되기 때문)
* 이 문제를 해결하기 위한 몇 가지 옵션
- useLayoutEffect를 useEffect로 바꾼다. 이럴 경우에 React가 페인트를 막지 않고 초기 렌더링 결과를 표시해도 괜찮다고 알려주기 때문(Effect가 실행되기 전에 원래 HTML이 보이게 되므로) ???
- 컴포넌트를 클라이언트 전용으로 표시하기. 서버 렌더링 중에 가장 가까운 <Suspense> 경계까지의 콘텐츠를 로딩 폴백으로 대체하도록 React에게 지시할 수 있다.
- hydration 후에만 useLayoutEffect를 사용하여 컴포넌트 렌더링 하기. 서버에서 hydration이 진행되는 동안 사용자는 useLayoutEffect를 호출하지 않는 FallbackContent를 보게되고, React는 클라이언트에서만 실행되기 때문에, useLayoutEffect를 호출하는 RealContent로 대체힐수 있다.
// isMounted state 선언
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
useLayoutEffect(() => {
// 클라이언트에서만 실행되어야 하는 로직을 작성
// 예: DOM 조작, 애니메이션 시작 등
}, []);
- 또는 컴포넌트를 외부 데이터 저장소와 동기화하고 레이아웃 측정이 아닌 다른 이유로 useLayoutEffect에 의존하는 경우에는, useSyncExternalStore를 고려할 수 있다.
* 참고 : React 공식문서(https://react-ko.dev/learn)
'이것저것 스터디📚 > React - 공식 문서' 카테고리의 다른 글
React 공식문서 -useDeferredValue (0) | 2023.10.11 |
---|---|
React 공식문서 -useInsertionEffect (0) | 2023.10.05 |
React 공식문서 -useTransition (0) | 2023.10.04 |
React 공식문서 -startTransition (0) | 2023.09.20 |
React 공식문서 -forwardRef (0) | 2023.09.20 |