--- id: wiki-2026-0508-render-props title: Render Props category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Function as Child, Children as Function, FaCC] duplicate_of: none source_trust_level: A confidence_score: 0.88 verification_status: applied tags: [react, pattern, component, composition, frontend] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: TypeScript framework: React 19 --- # Render Props ## 매 한 줄 > **"매 component 가 prop 으로 받은 function 을 호출해 무엇을 render 할지 결정"**. Michael Jackson 이 popularize 한 React 합성 패턴 (2017). 2018 Hooks 등장 후 매 logic-sharing 용도는 대부분 custom hook 으로 대체되었지만, 매 *render-time data injection* (animation, virtualization, headless UI) 에서는 매 2026 까지도 first-class 도구. ## 매 핵심 ### 매 정의 - 매 component 가 호출자에게 *어떻게 render 할지* 의 control 을 위임. - Function-typed prop (`children` 또는 `render`) 이 state/computation 을 인자로 받아 ReactNode 반환. - 매 inversion of control — provider 는 logic, consumer 는 view. ### 매 Hooks 와 의 관계 - 매 logic reuse 의 90%: custom hook 이 우월 (no nesting, easier types). - 매 render-time slot 패턴: render props 가 여전히 적합 — Framer Motion, react-virtual, Radix UI 등. - 매 headless UI (Headless UI, Radix, Ariakit) 는 render props + compound component 혼합. ### 매 응용 1. Animation: Framer Motion `` children function. 2. Virtualization: TanStack Virtual `` row renderer. 3. Form: react-hook-form ``. 4. Headless: Headless UI `{({active}) => ...}`. ## 💻 패턴 ### Basic render prop ```tsx type MouseTrackerProps = { render: (state: { x: number; y: number }) => React.ReactNode; }; function MouseTracker({ render }: MouseTrackerProps) { const [pos, setPos] = useState({ x: 0, y: 0 }); return (
setPos({ x: e.clientX, y: e.clientY })}> {render(pos)}
); } // usage

{x}, {y}

} /> ``` ### Children as function (FaCC) ```tsx type Props = { children: (state: { x: number; y: number }) => React.ReactNode }; function MouseTracker({ children }: Props) { const [pos, setPos] = useState({ x: 0, y: 0 }); return
setPos({ x: e.clientX, y: e.clientY })}>{children(pos)}
; } {({ x, y }) =>

{x}, {y}

}
``` ### TanStack Virtual (real-world 2026) ```tsx import { useVirtualizer } from '@tanstack/react-virtual'; function List({ items }: { items: string[] }) { const ref = useRef(null); const v = useVirtualizer({ count: items.length, getScrollElement: () => ref.current, estimateSize: () => 32, }); return (
{v.getVirtualItems().map((vi) => (
{items[vi.index]}
))}
); } ``` ### react-hook-form Controller ```tsx import { Controller, useForm } from 'react-hook-form'; function Form() { const { control } = useForm<{ name: string }>(); return ( ( )} /> ); } ``` ### Headless UI Menu (compound + render prop) ```tsx import { Menu } from '@headlessui/react'; Options {({ active }) => ( Edit )} ``` ### Generic render prop with typed slot ```tsx function DataLoader({ url, children, }: { url: string; children: (s: { data: T | null; loading: boolean; error: Error | null }) => React.ReactNode; }) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch(url).then(r => r.json()).then(setData).catch(setError).finally(() => setLoading(false)); }, [url]); return <>{children({ data, loading, error })}; } ``` ### Hook equivalent (when to prefer) ```tsx function useMouse() { const [pos, setPos] = useState({ x: 0, y: 0 }); const onMouseMove = (e: React.MouseEvent) => setPos({ x: e.clientX, y: e.clientY }); return { pos, onMouseMove }; } function MyView() { const { pos, onMouseMove } = useMouse(); return
{pos.x},{pos.y}
; } ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Logic 만 공유 | **Custom hook** (default since 2019) | | DOM/JSX slot 주입 필요 | Render props | | Generic library (virtualizer, animator) | Render props | | Headless UI primitive | Render props + compound | | Class component legacy | Render props (hook 불가) | **기본값**: 매 hook 우선, 매 render slot 이 진짜 필요할 때만 render props. ## 🔗 Graph - 부모: [[React Patterns]] · [[Component Composition (React)]] - 변형: [[Custom Hooks]] · [[Component-Composition|Compound Components]] - 응용: [[Headless UI]] · [[react-hook-form]] - Adjacent: [[Inversion of Control]] · [[Slot Pattern]] ## 🤖 LLM 활용 **언제**: 매 library API 설계, 매 generic data-injection slot, 매 animation choreography. **언제 X**: 매 단순 logic share — hook 으로 충분. 매 callback hell 위험. ## ❌ 안티패턴 - **Render prop hell**: 매 nesting 5단계 — flatten 또는 hook. - **Inline function in render**: 매 매 render 마다 새 function — child memoization 깨짐, `useCallback` 또는 module-scope. - **Both `children` and `render`**: 매 ambiguous API — 하나만. - **Hook 으로 충분한데 render prop**: 매 over-engineering. - **Type any**: 매 generic slot 의 type erasure — `` generic 사용. ## 🧪 검증 / 중복 - Verified: React docs (legacy section), TanStack Virtual, react-hook-form, Headless UI 공식 docs (2026). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — render props vs hooks, real-world 2026 examples |