Advanced Patterns
These three patterns predate (in two cases) or coexist with the hooks covered throughout this course, and component libraries you'll use professionally still rely on all three in places. Worth recognizing each one on sight, even where a custom hook (Intermediate Chapter 4) would now be the more natural choice for new code.
Compound Components — Sharing State Implicitly
A compound component is a set of components designed to be used together, internally coordinating via Context the way Tabs does here — the consumer never sees activeTab or passes it anywhere explicitly; Tabs, Tabs.Tab, and Tabs.Panel all share it transparently through context set up entirely inside the family. Attaching Tab and Panel as properties on Tabs (Tabs.Tab = Tab) is purely a naming/organization convention, making clear which pieces belong together without a separate import for each. This is genuinely still the standard approach for multi-part UI widgets in real component libraries (tabs, accordions, dropdown menus).
Render Props — Letting the Consumer Control Rendering
Here, children isn't JSX at all — it's a function, called with whatever data/behavior Toggle wants to expose, returning the JSX to actually render. This particular shape ("children as a function") is the most common variant of the render props pattern; the same idea also appears as a separately-named prop (render={({ on, toggle }) => ...}) rather than children specifically. Either way, Toggle owns the boolean state and the toggle logic, while the caller decides completely freely what that state should look like on screen — a button, a checkbox, anything.
Toggle example above is solving the exact same problem as Intermediate Chapter 4's useToggle hook — reusable toggle behavior, usable from anywhere. A custom hook is generally the more direct modern choice for sharing behavior specifically; render props remain genuinely useful when a component needs to share both behavior and markup structure together (a list component handling virtualization/scrolling, exposing a render prop per row), which a hook alone can't do.
Higher-Order Components — A Function That Returns a Component
A higher-order component is a function taking a component and returning a new component with extra behavior layered on — here, withLoading intercepts the isLoading prop and shows a loading message instead of rendering the wrapped component at all, until it becomes false. This pattern predates hooks entirely, and was the standard way to share cross-cutting behavior (loading states, authentication checks, data injection) before useState/useEffect existed in their current form.
withLoading does, a custom hook does more directly — no wrapper component, no extra layer in the component tree showing up in debugging tools, and no prop-name collisions between what the HOC injects and what the wrapped component already expects. New code today reaches for a custom hook (Intermediate Ch 4) for this kind of cross-cutting concern almost every time; recognizing the HOC pattern still matters for reading and maintaining existing libraries and codebases that predate hooks.
| Pattern | Still common today? | Modern alternative |
|---|---|---|
| Compound components | Yes — multi-part UI widgets | (itself, still the standard approach) |
| Render props | Occasionally — shared behavior + markup structure | A custom hook, when only behavior needs sharing |
| HOCs | Rarely in new code — mostly legacy | A custom hook, almost always |
Coding Challenges
Build a compound Tabs component family (Tabs, Tabs.Tab, Tabs.Panel) sharing active-tab state via Context internally, with at least three tabs.
📄 View solutionBuild a render-props Toggle component (children as a function exposing { on, toggle }), and use it twice to build two completely different UIs — a button showing ON/OFF, and a checkbox — both reusing the exact same Toggle logic.
📄 View solutionBuild the withLoading HOC from this chapter and use it to wrap a simple component. Then write a useLoading-style custom hook achieving the same "show loading until ready" behavior, and compare the two approaches.
📄 View solutionChapter 5 Quick Reference
- Compound components — a family of components sharing implicit state via internal Context (
Tabs.Tab,Tabs.Panel) - Render props — a prop (often
children) that's a function, letting the caller control rendering while the component owns behavior - HOCs — a function taking a component, returning a new wrapped component with added behavior
- Compound components remain the standard for multi-part UI widgets; render props occasionally still earn their place
- HOCs are largely legacy — a custom hook (Intermediate Ch 4) almost always replaces them in new code
- Next chapter: performance profiling — measuring before optimizing, with React's own DevTools profiler