import React, { useEffect, useLayoutEffect, useRef } from 'react'; type Priority = 'high' | 'low'; export function HydrationBoundary({ priority, hydrate = true, hydratePriority = 'all', onHydrate, children, }: { priority: Priority; hydrate?: boolean; hydratePriority?: Priority | 'all'; onHydrate?: (p: Priority) => void; children: React.ReactNode; }) { // TODO: active = hydrate && (hydratePriority === 'all' || hydratePriority === priority) const active = false; // TODO: high 우선순위가 항상 먼저 hydrate되도록 보장하세요. // - useLayoutEffect를 사용해 high는 즉시 onHydrate 호출 // - low는 queueMicrotask 또는 setTimeout으로 한 틱 뒤로 미뤄 // hydratePriority='all'일 때 high가 먼저 호출됨을 보장 useLayoutEffect(() => { if (!active) return; if (priority === 'high') { // TODO: onHydrate?.('high') } else { // TODO: queueMicrotask(() => onHydrate?.('low')) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [active, priority]); return ( <div data-testid={`boundary-${priority}`} data-active={active ? 'true' : 'false'} // active=false면 클릭/포커스 등 인터랙션을 막습니다 onClickCapture={active ? undefined : (e) => { e.stopPropagation(); e.preventDefault(); }} style={{ pointerEvents: active ? 'auto' : 'none' }} > {children} </div> ); }
Tests