렌더 흐름에서 규칙이 걸리는 자리
① render — 유지돼야 하는 값은 useMemo 가 아니라 state
useMemo(getRandomColors, []) 로 만든 값이 HMR 뒤에 바뀐다.1
const resolved = resolveTheme(mode, systemDark) // 순수 파생은 그냥 계산
const [colors] = useState(getRandomColors) // 유지가 곧 correctness 면 state
② useLayoutEffect — 서버 경고는 shim 으로 (React 18 이하)2
const useIsoLayoutEffect =
typeof window !== 'undefined' ? useLayoutEffect : useEffect
③ useEffect — 이벤트는 노드가 사는 window 에
window.open·포털로 다른 창에 렌더해도 window.addEventListener 는 원래 창을 듣는다.3
const win = ref.current?.ownerDocument.defaultView ?? window
멀티윈도우로 쓰일 수 있는 라이브러리 컴포넌트에만 필요하다.
④ ref 콜백 — cleanup 을 반환한다 (React 19)4
<div
ref={(node) => {
const ctrl = new AbortController()
node.addEventListener('scroll', onScroll, { signal: ctrl.signal })
return () => ctrl.abort()
}}
/>
Footnotes
-
“For example, in development, React throws away the cache when you edit the file of your component. Both in development and in production, React will throw away the cache if your component suspends during the initial mount.” / “This should be fine if you rely on
useMemosolely as a performance optimization. Otherwise, a state variable or a ref may be more appropriate.” / “In the future, React may add more features that take advantage of throwing away the cache—for example, if React adds built-in support for virtualized lists in the future, it would make sense to throw away the cache for items that scroll out of the virtualized table viewport.” (useMemo — React) ↩ -
React 19.0.0 에서 경고가 빠졌다 — “Remove layout effect warning on server” (CHANGELOG — React 19.0.0) ↩
-
ownerDocument는 “returns the top-level document object of the node”,defaultView는 “returns the window object associated with a document, ornullif none is available.” (Node.ownerDocument — MDN · Document.defaultView — MDN) ↩ -
“When that
<div>DOM node is removed, React will call your the cleanup function returned from the callback.” / “React 19 added cleanup functions for ref callbacks.” (Common components — React) ↩