
useSyncExternalStore 훅은 React 18에서 등장한 신규 훅으로, 리액트가 외부 저장소의 변경사항을 "구독"할 수 있도록 도와주는 훅이다.
18버전에 들어오면서 리액트는 useTransition, useDeferredValue와 같이 렌더링을 일시중지하거나, 뒤로 미루는 등의 동시성 최적화를 도와줄 수 있는 훅들이 사용가능해졌다.
하지만 리액트에서 이렇게 동시성 렌더링이 가능해지면서, 외부 저장소의 데이터를 참조하는 컴포넌트를 렌더링할때 같은 시기에 렌더링을 했지만, 서로 다른 시점의 데이터를 참조할 수도 있는 Data Tearing 문제가 발생할 수 있게됐다.
이 문제를 해결해주는 훅이 바로 useSyncExternalStore 훅이다.
useSyncExternalStore(
subscribe: (callback) => Unsubscribe,
getSnapshot: () => State,
getServerSnapshot?: () => State
)
subscribeuseSyncExternalStore가 이 훅을 사용하는 컴포넌트를 리렌더링한다.getSnapshotObject.is로 비교해 정말로 값이 변경됐다면 컴포넌트를 리렌더링한다.getServerSnapshot일반적인 애플리케이션을 작성하는 상황에서는 크게 쓸 일이 많지만, 상태관리 라이브러리를 작성하거나, 리액트 외부의 무언가에 대한 값이 필요하고, 값이 변경될때마다 리렌더링이 수행되어야하는 케이스에 사용하면 적절하다.
DOM, 글로벌 변수, 외부 상태관리 라이브러리 등을 사용할 때 사용할 수 있으며, 아래는 예시로 작성해본 window.innerHeight 값에 대한 useInnerHeight 훅이다.
import { useSyncExternalStore } from "react";
function subscribe(callback) {
window.addEventListener("resize", callback);
return () => {
window.removeEventListener("resize", callback);
};
}
const useInnerHeight = () => {
const innerHeight = useSyncExternalStore(
subscribe,
() => window.innerHeight
);
return innerHeight;
};
export default useInnerHeight;
첫번째 인수인 subscribe에는 resize 이벤트를 활용해서 innerHeight 값이 변경되는 상황에서 리렌더링이 발생할 수 있도록 해주고, 두번째 인수인 getSnapshot으로 window.innerHeight 값 반환을 통해 최신값을 받아올 수 있도록 커스텀 훅을 작성했다.