Notice
Recent Posts
Recent Comments
Link
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

효뚜르팝의 Dev log

[React 공식문서로 공부하기5] useEffect와 useLayoutEffect 본문

TIL

[React 공식문서로 공부하기5] useEffect와 useLayoutEffect

hyodduru 2024. 3. 17. 18:11
리액트 공식문서를 읽고 정리한 글입니다. 
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