useEffect
를 이용해 블로그 구독 버튼 스타일을 출력하는 과정에서 화면 깜박임이 발생했다.
탭을 이동할 때마다 발생하는 보기 싫은 깜박임을 해결하기 위해 찾아본 결과, 사용자에게 보여지는 DOM의 변경이 있을 때 사용 가능한 useLayoutEffect
훅을 알게 되었다.
useEffect
와 useLayoutEffect
는 거의 동일하게 작동하는데, 두 훅의 차이점은 바로 이펙트의 호출 타이밍에 있다.
useEffect
💡 effect 타이밍
componentDidMount와 componentDidUpdate와는 다르게, useEffect로 전달된 함수는 지연 이벤트 동안에 레이아웃 배치와 그리기를 완료한 후 발생합니다. 이것은 구독이나 이벤트 핸들러를 설정하는 것과 같은 다수의 공통적인 side effects에 적합합니다. 왜냐면 대부분의 작업이 브라우저에서 화면을 업데이트하는 것을 차단해서는 안 되기 때문입니다.
그렇지만, 모든 effect가 지연될 수는 없습니다. 예를 들어 사용자에게 노출되는 DOM 변경은 사용자가 노출된 내용의 불일치를 경험하지 않도록 다음 화면을 다 그리기 이전에 동기화 되어야 합니다. 이런 종류의 effect를 위해 React는 useLayoutEffect라는 추가적인 Hook을 제공합니다. 그것은 useEffect와 동일한 시그니처를 가지고 있고 그것이 수행될 때에만 차이가 납니다.
Hooks API Reference
useEffect
는 렌더가 화면에 paint된 후, 비동기적으로 실행된다.
useEffect
실행화면이 미리 paint된 후에 실행되기 때문에, 만약 useEffect에 DOM요소에 영향을 주는 코드가 있다면 화면 깜박임이 발생할 수 있는 것이다.
useLayoutEffect
이 함수의 시그니처는 useEffect와 동일하긴 한데, 모든 DOM 변경 후에 동기적으로 발생합니다. 이것은 DOM에서 레이아웃을 읽고 동기적으로 리렌더링하는 경우에 사용하세요. useLayoutEffect의 내부에 예정된 갱신은 브라우저가 화면을 그리기 이전 시점에 동기적으로 수행될 것입니다.
Hooks API Reference
반면 useLayoutEffect
는 컴포넌트 렌더 후, 화면에 paint되기 전에 동기적으로 실행된다.
useLayoutEffect
실행, React는 완료될 때까지 기다림동기적으로 실행되어 해당 이펙트가 다 수행되고 난 후에 paint되기 때문에, DOM요소에 영향을 주는 코드가 있다면 useLayoutEffect
을 사용하여 깜박임을 방지할 수 있다.
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