Files
2nd/10_Wiki/Topics/Programming & Language/Escape Hatch (탈출구).md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

6.0 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-escape-hatch-탈출구 Escape Hatch (탈출구) 10_Wiki/Topics verified self
React escape hatch
useRef escape hatch
useEffect escape hatch
none A 0.9 applied
react
hooks
useref
useeffect
framework-design
2026-05-10 pending
language framework
TypeScript React

Escape Hatch (탈출구)

매 한 줄

"매 framework 가 model 외의 reality 의 reach 매 escape hatch". React 의 escape hatch — useRef, useEffect, flushSync, ref callback 의 declarative model 외의 imperative DOM/non-React system 의 bridge. 매 2026 React 19 (Activity API, useOptimistic) 의 도입 매 escape hatch 의 사용 빈도 의 감소 but 매 여전히 essential.

매 핵심

매 왜 필요

  • React model: declarative — UI = f(state).
  • 매 reality 매 imperative — DOM focus, video play, third-party (D3, Chart.js, Three.js), browser API (IntersectionObserver).
  • 매 escape hatch 의 controlled bridge 의 제공.

매 React 의 4 hatch

  • useRef: 매 mutable container 매 re-render trigger 없음.
  • useEffect: 매 commit 후 의 side-effect — 매 subscription, manual DOM, external system.
  • flushSync: 매 sync update 의 force — 매 layout measurement before paint.
  • ref callback: 매 mount/unmount lifecycle 의 ref level access.

매 응용

  1. Third-party library integration (D3, Three.js).
  2. Imperative DOM (focus, scroll, select).
  3. Subscription (WebSocket, EventSource).

💻 패턴

useRef Mutable Value

function Stopwatch() {
  const intervalRef = useRef<number | null>(null)
  const [time, setTime] = useState(0)

  const start = () => {
    if (intervalRef.current) return
    intervalRef.current = window.setInterval(() => setTime((t) => t + 1), 1000)
  }
  const stop = () => {
    if (intervalRef.current) clearInterval(intervalRef.current)
    intervalRef.current = null
  }
  return <button onClick={start}>{time}</button>
}

useRef DOM Reference

function AutoFocus() {
  const inputRef = useRef<HTMLInputElement>(null)
  useEffect(() => {
    inputRef.current?.focus()
  }, [])
  return <input ref={inputRef} />
}

useEffect External System

function ChatRoom({ roomId }: { roomId: string }) {
  useEffect(() => {
    const conn = createConnection(roomId)
    conn.connect()
    return () => conn.disconnect() // 매 cleanup essential
  }, [roomId])
  return <h1>Welcome to {roomId}</h1>
}

Third-party Integration (Three.js)

function ThreeScene() {
  const containerRef = useRef<HTMLDivElement>(null)
  useEffect(() => {
    const scene = new THREE.Scene()
    const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000)
    const renderer = new THREE.WebGLRenderer()
    renderer.setSize(800, 600)
    containerRef.current?.appendChild(renderer.domElement)

    let raf: number
    const animate = () => {
      raf = requestAnimationFrame(animate)
      renderer.render(scene, camera)
    }
    animate()

    return () => {
      cancelAnimationFrame(raf)
      renderer.dispose()
      containerRef.current?.removeChild(renderer.domElement)
    }
  }, [])
  return <div ref={containerRef} />
}

flushSync (force sync)

import { flushSync } from "react-dom"

function ScrollToBottom() {
  const [items, setItems] = useState<string[]>([])
  const listRef = useRef<HTMLUListElement>(null)

  const addItem = (text: string) => {
    flushSync(() => {
      setItems((prev) => [...prev, text])
    })
    // 매 flushSync 후 매 DOM 매 updated 의 guaranteed
    listRef.current?.scrollTo(0, listRef.current.scrollHeight)
  }
  return (/* ... */)
}

Ref Callback (mount/unmount)

function ObservedItem({ onVisible }: { onVisible: () => void }) {
  const refCallback = useCallback((node: HTMLDivElement | null) => {
    if (!node) return
    const obs = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) onVisible()
    })
    obs.observe(node)
    return () => obs.disconnect() // React 19+ cleanup
  }, [onVisible])
  return <div ref={refCallback}>Observed</div>
}

useImperativeHandle (parent 의 controlled API)

type ModalHandle = { open: () => void; close: () => void }

const Modal = forwardRef<ModalHandle>((_, ref) => {
  const [open, setOpen] = useState(false)
  useImperativeHandle(ref, () => ({
    open: () => setOpen(true),
    close: () => setOpen(false),
  }), [])
  return open ? <div>Modal</div> : null
})

function App() {
  const modalRef = useRef<ModalHandle>(null)
  return <button onClick={() => modalRef.current?.open()}>Open</button>
}

매 결정 기준

상황 Hatch
Mutable value 매 no re-render useRef
DOM focus/scroll useRef + useEffect
External lib (D3/Three.js) useEffect
Sync DOM measurement flushSync
Mount/unmount lifecycle ref callback
Parent imperative API useImperativeHandle

기본값: 매 declarative 매 first — 매 hatch 매 last resort.

🔗 Graph

  • 부모: React
  • 변형: Vue Composition API · Solid Signals
  • 응용: IntersectionObserver
  • Adjacent: useEffect · useRef

🤖 LLM 활용

언제: 매 third-party imperative library 의 React 의 integration, DOM 의 manual control. 언제 X: 매 pure UI state — 매 useState/useReducer 의 사용.

안티패턴

  • useRef 매 derived state: 매 useState 또는 useMemo 매 사용.
  • useEffect 매 data fetch (cascading): 매 React Query / RSC 매 사용.
  • Stale ref read in render: 매 ref.current 의 render 의 read 매 X.
  • Cleanup 의 omit: 매 memory leak — 매 return 매 always.

🧪 검증 / 중복

  • Verified (React 공식 docs "Escape Hatches" chapter, React 19 — 2026).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — React 19 escape hatch 4종 + 패턴 작성