[developic] useLayoutEffect 훅으로 화면 깜박임 해결

sue·2021년 8월 5일
1

developic project

목록 보기
24/28

useEffect를 이용해 블로그 구독 버튼 스타일을 출력하는 과정에서 화면 깜박임이 발생했다.

탭을 이동할 때마다 발생하는 보기 싫은 깜박임을 해결하기 위해 찾아본 결과, 사용자에게 보여지는 DOM의 변경이 있을 때 사용 가능한 useLayoutEffect 훅을 알게 되었다.

useEffectuseLayoutEffect는 거의 동일하게 작동하는데, 두 훅의 차이점은 바로 이펙트의 호출 타이밍에 있다.

useEffect

useEffect
💡 effect 타이밍
componentDidMount와 componentDidUpdate와는 다르게, useEffect로 전달된 함수는 지연 이벤트 동안에 레이아웃 배치와 그리기를 완료한 후 발생합니다. 이것은 구독이나 이벤트 핸들러를 설정하는 것과 같은 다수의 공통적인 side effects에 적합합니다. 왜냐면 대부분의 작업이 브라우저에서 화면을 업데이트하는 것을 차단해서는 안 되기 때문입니다.

그렇지만, 모든 effect가 지연될 수는 없습니다. 예를 들어 사용자에게 노출되는 DOM 변경은 사용자가 노출된 내용의 불일치를 경험하지 않도록 다음 화면을 다 그리기 이전에 동기화 되어야 합니다. 이런 종류의 effect를 위해 React는 useLayoutEffect라는 추가적인 Hook을 제공합니다. 그것은 useEffect와 동일한 시그니처를 가지고 있고 그것이 수행될 때에만 차이가 납니다.
Hooks API Reference

useEffect는 렌더가 화면에 paint된 후, 비동기적으로 실행된다.

  1. 렌더링 유발(상태 변경 또는 상위 렌더링)
  2. React가 컴포넌트 렌더링
  3. 화면이 시각적으로 업데이트(paint)
  4. useEffect 실행

화면이 미리 paint된 후에 실행되기 때문에, 만약 useEffect에 DOM요소에 영향을 주는 코드가 있다면 화면 깜박임이 발생할 수 있는 것이다.

useLayoutEffect

useLayoutEffect
이 함수의 시그니처는 useEffect와 동일하긴 한데, 모든 DOM 변경 후에 동기적으로 발생합니다. 이것은 DOM에서 레이아웃을 읽고 동기적으로 리렌더링하는 경우에 사용하세요. useLayoutEffect의 내부에 예정된 갱신은 브라우저가 화면을 그리기 이전 시점에 동기적으로 수행될 것입니다.
Hooks API Reference

반면 useLayoutEffect는 컴포넌트 렌더 후, 화면에 paint되기 전에 동기적으로 실행된다.

  1. 렌더링 유발(상태 변경 또는 상위 렌더링)
  2. React가 컴포넌트 렌더링
  3. useLayoutEffect 실행, React는 완료될 때까지 기다림
  4. 화면이 시각적으로 업데이트(paint)

동기적으로 실행되어 해당 이펙트가 다 수행되고 난 후에 paint되기 때문에, DOM요소에 영향을 주는 코드가 있다면 useLayoutEffect을 사용하여 깜박임을 방지할 수 있다.

요약

  • useLayoutEffect: 화면에 DOM이 그려지기(paint) 전에 이펙트가 호출되기 때문에, DOM을 변경해야 할 때 사용한다.
  • useEffect: 화면에 DOM이 그려진(paint) 후 이펙트를 호출하기 때문에, DOM과 상호작용할 필요가 없거나, DOM 변경사항을 관찰할 필요 없는 경우(대부분의 경우)에 사용한다.

코드 적용 예시

const [isFollowing, setIsFollowing] = useState(false);

useLayoutEffect(() => {
   if (!blogUserData?.id) return;
   if (userData?.writers.find(following => following.id == blogUserData.id)) {
     setIsFollowing(true);
   } else {
     setIsFollowing(false);
   }
 }, [blogUserData?.id, userData?.writers]);

useLayoutEffect로 변경 후, 깜박임이 사라진 것을 볼 수 있다.

References

0개의 댓글