useSyncExternalStore는 React 밖에 있는 상태(외부 스토어(External Store), 브라우저 API(Application Programming Interface))를 구독해 컴포넌트와 동기화하는 훅이다. 동시성 렌더링(Concurrent Rendering)에서도 모든 컴포넌트가 같은 스냅샷을 보게 보장해 상태 찢어짐(Tearing)을 막는다(React 18+).
function subscribe(callback) {
window.addEventListener('online', callback)
window.addEventListener('offline', callback)
return () => {
window.removeEventListener('online', callback)
window.removeEventListener('offline', callback)
}
}
const isOnline = useSyncExternalStore(
subscribe, // 변경 알림 등록, 해제 함수 반환
() => navigator.onLine, // getSnapshot: 현재 값
() => true, // getServerSnapshot: SSR·하이드레이션용
)- React는 렌더할 때
getSnapshot()을 읽고, 커밋 직전에 다시 읽어 값이 달라졌으면 렌더 결과를 버리고 다시 렌더한다 getSnapshot은 값이 그대로면 같은 참조를 돌려줘야 한다. 매번 새 객체를 만들면 계속 바뀐 것으로 보여 무한 렌더가 된다subscribe는 컴포넌트 밖에 두거나 고정해야 렌더마다 재구독하지 않는다- 브라우저 쪽 예: 온라인 상태, 창 크기, 다른 탭에서 바뀐 localStorage(
storage이벤트, localStorage와 sessionStorage) - 직접 쓸 일은 많지 않다. react-redux 8 이상, Zustand 4 이상 같은 상태 라이브러리가 내부에서 이 훅으로 스토어를 연결한다(Redux 이후의 상태 관리 선택)
- 구독과 알림 구조는 옵저버 패턴 그대로다