useEffect와 useLayoutEffect


유저의 팔로우 목록 모달을 만들던 중, UI가 렌더가 될 때 깜빡이면서 내용이 달라졌다.

이 부분이 매우 거슬렸기 때문에 해결법을 찾았다.

결론부터 말하자면, useEffect와 useLayoutEffect는 실행 시점만 다르다.

✨ useEffect

useEffect 훅은 컴포넌트가 렌더링된 후, DOM을 업데이트 하고 paint가 완료된 후 비동기적으로 실행된다.

1useEffect(() => {
2	// 데이터 페칭
3  const fetchData = async () => {
4    	const response = await fetch('/api/data');
5    	const data = await response.json();
6    	setData(data);
7  };
8  
9  fetchData();
10},[])

데이터가 state에 반영되고 state 변경으로 인해 컴포넌트가 다시 렌더링 되기 때문에 화면이 깜빡이면서 바뀐다.

✨ useLayoutEffect

useLayoutEffect 훅은 컴포넌트가 렌더링되고 DOM이 업데이트된 직후 paint 되기 전에 동기적으로 실행된다.

1useLayoutEffect(() => {
2  if (data) {
3      const element = document.getElementById('my-element');
4      if (element) {
5        element.style.height = `${data.length * 10}px`; // DOM 조작
6      }
7  }
8}, [data])

데이터가 state에 반영되고 state 변경으로 인해 컴포넌트가 다시 렌더링 되지만, paint가 되기 이전에 동기적으로 실행되었기 때문에 사용자는 화면의 깜빡임을 보지 않는다.

✔ 프로젝트에 어떻게 적용했냐면

1  useLayoutEffect(() => {
2    if (modalType === 'followers') {
3      setFollowData(follower?.pages);
4    }
5    if (modalType === 'followees') {
6      setFollowData(followee?.pages);
7    }
8  }, [modalType]);

처음에는 useEffect훅을 사용했더니, 모달의 타입이 바뀔때 마다 이전 상태값이 잠깐 보였다가 바뀌었다.

useLayoutEffect 훅을 사용하여 브라우저가 화면을 다시 그리기 전에 상태값이 반영되어 깜빡임 없이 내용을 볼수 있게 된다.

❗ 주의할 점

  1. useLayoutEffect는 동기적으로 실행되므로 복잡한 DOM조작이 많은 경우 컴포넌트가 렌더링될 때 까지 다음 렌더링이 지연될 수 있다.
    그래서 DOM 조작이 길어질 경우 화면에 paint가 되지 않아 사용자 경험을 저하시킬 수 있다.
  2. 데이터 페칭과 같은 일반적인 사이드 이펙트를 실행할 때는 useEffect를 사용하는 것이 좋다.