효뚜르팝의 Dev log
[React 공식문서로 공부하기5] useEffect와 useLayoutEffect 본문
리액트 공식문서를 읽고 정리한 글입니다.
https://react-ko.dev/reference/react/useEffect
useEffect – React
The library for web and native user interfaces
react-ko.dev
useEffect
컴포넌트를 외부 시스템과 동기화할 수 있는 React 훅
- useEffect는 undefined를 반환한다.
- useEffect는 훅이므로 컴포넌트의 최상위 레벨 혹은 자체 훅에서만 호출할 수 있다. 반복문이나 조건문 내부에서는 호출할 수 없다.
- Effect가 상호작용(예:클릭)으로 인한 것이 아니라면, React는 브라우저가 Effect를 실행하기 전에 업데이트된 화면을 먼저 그리도록 한다. Effect가 시각적인 작업을 하고 있고, 지연이 눈에 띄는 경우(예: 깜박임), useEffect를 useLayoutEffect로 대체해야 한다.
- 상호작용(예:클릭)으로 인해 Effect가 발생한 경우에도, 브라우저는 Effect 내부의 state 업데이트를 처리하기 전에 화면을 다시 그릴 수 있다. 만약 브라우저가 다시 화면을 칠하지 못하도록 차단해야하는 경우라면 useEffect를 useLayoutEffect로 바꾸어야 한다.
- Effect는 클라이언트에서만 실행된다. 서버 렌더링에는 실행되지 않는다.
- 외부 시스템에 연결하지 않는다면 Effect가 필요하지 않을 수 있다. (외부 시스템 예 : setInterval, window.addEventListner, animation.start(), 채팅 서비스 등)
Effect로 데이터 페칭을 하면 좋지 않은 이유
- Effect는 서버에서 실행되지 않는다. 클라이언트 컴퓨터는 모든 Javascript를 다운로드하고 앱을 렌더링해야만 데이터 로드를 해야하여 비효율적임.
- Effect에서 직접 페칭하면 네트워크 워터풀을 만들기 쉽다. 부모 컴포넌트 렌더링 이후 일부 데이터를 페칭하고 이후 자식 컴포넌트를 렌더링 후 데이터 페칭을 하여 모든 데이터를 병렬로 페칭하는 것도다 훨씬 속도가 느림.
- 데이터를 미리 로드하거나 캐시하는게 불가능함. 컴포넌트 마운트가 해제 후 다시 마운트를 할 시 데이터를 가져와야 함.
-> 프레임워크 빌트인 데이터 페칭 메커니즘 혹은 client-side 캐시를 사용하거나 구축할 수 있음
Effect에 “반응”하지 않고도 Effect에서 최신 props와 state를 읽고 싶을 때
ex) url이 변경될 때만 방문기록을 기록하고 싶은 경우
function Page({ url, shoppingCart }) {
useEffect(() => {
logVisit(url, shoppingCart.length);
}, [url, shoppingCart]); // ✅ All dependencies declared
// ...
}
-> useEffectEvent 사용하여 Effect Event를 선언하고 shoppingCart를 읽는 코드 그 안으로 이동시킨다.
function Page({ url, shoppingCart }) {
const onVisit = useEffectEvent(visitedUrl => {
logVisit(visitedUrl, shoppingCart.length)
});
useEffect(() => {
onVisit(url);
}, [url]); // ✅ All dependencies declared
// ...
}
Effect Event는 반응형이 아니므로 항상 의존성에서 제외해야 한다.
useEffect로 무한 렌더링이 발생할 때
- 렌더링에 사용되지 않는 일부 데이터를 추적해야 하는 경우 리렌더링을 촉발하지 않는 ref가 더 적합할 수 있다.
- state 업데이트로 인해 Effect의 의존성 중 하나가 변경되는 것은 아닌지 확인해보기
useLayoutEffect
https://react-ko.dev/reference/react/useLayoutEffect
useLayoutEffect – React
The library for web and native user interfaces
react-ko.dev
useLayoutEffect는 브라우저가 화면을 다시 채우기 전에 실행되는 버전의 useEffect이다.
ex)
마우스오버 시 요소 옆에 툴팁이 표시되는 경우, 올바른 최종 위치를 알기 위해서는 툴팁의 높이를 알아야 함.
1. 툴팁을 원하는 위치에 렌더링
2. 높이를 측정하고 툴팁을 배치할 위치를 결정
3. 올바른 위치에 툴팁을 다시 렌더링
-> 이 모든 작업을 브라우저가 화면을 다시 그리기 전에 이루어져야 함
function Tooltip() {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0); // 아직 실제 height 값을 모름
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height); // 실제 높이를 알았으니 이제 리렌더링 함
}, []);
// ...아래에 작성될 렌더링 로직에 tooltipHeight를 사용
}
- useLayoutEffect는 브라우저가 다시 그리는 것을 차단한다. (useEffect는 차단하지 않음)
"useLayoutEffect" does nothing on the server 와 같은 에러를 마주했을 때
SSR을 사용하는 경우 위와 같은 에러를 마주할 수 있다.
-> 서버 렌더링의 경우 React 앱은 초기 렌더링을 위해 서버의 HTML로 렌더링이 되어 JS 코드가 로드가 되기 전에 HTML을 표시할 수 있음. 문제는 이때 서버에 레이아웃 정보가 없기 때문에 이때 이와 같은 에러가 발생함
이를 해결하기 위해 다음의 방법을 사용할 수 있다.
- useEffect로 대체
- client 전용으로 표시하기 -> 이렇게 하면 서버 렌더링 중 가장 가까운 <Suspense> 경계까지의 컨텐츠를 폴백으로 대체하도록 React에 지시함
- hydration 후에만 useLayoutEffect 사용해서 컴포넌트를 렌더링할 수 있음
- 컴포넌트를 외부 데이터 저장소와 동기화하고 레이아웃 측정이 아닌 다른 이유로 useLayoutEffect에 의존하는 경우 서버렌더링을 지원하는 "useSyncExternalStore" 고려해보기
참고) hydration에 대한 설명
https://simsimjae.tistory.com/389
'TIL' 카테고리의 다른 글
| [유데미(udemy) - React CleanCode] State (0) | 2024.04.09 |
|---|---|
| [React 공식문서로 공부하기6] lazy와 memo (3) | 2024.03.17 |
| [React 공식문서로 공부하기4] Escape Hatches 탈출구 (5) | 2024.03.04 |
| [React 공식문서로 공부하기3] Managing State (1) | 2024.02.25 |
| [React 공식문서로 공부하기2] Adding Interactivity 상호작용 추가하기 (1) | 2024.02.20 |