0Pricing
Frontend Academy · Lesson

Render Props and HOC Patterns

Pass a render function as a prop to inject UI, and wrap components in Higher-Order Components to inject behaviour without modifying the original.

Render Props and HOC Patterns is a free Frontend Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Frontend Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Two Classic Reuse Patterns

Before hooks (React 16.8), reusing stateful logic meant either Higher-Order Components (HOCs) or render props. They're rare in new code but you still meet them in legacy codebases and many libraries.

Render Props — The Idea

A component accepts a function as a prop (commonly named render or children) and calls it with internal state. The consumer decides what to render with that state.

function Mouse({ render }) {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  useEffect(() => {
    const handler = (e) => setPos({ x: e.clientX, y: e.clientY });
    window.addEventListener('mousemove', handler);
    return () => window.removeEventListener('mousemove', handler);
  }, []);
  return render(pos);
}

// Usage:
<Mouse render={({ x, y }) => <p>{x}, {y}</p>} />

children as a Function

The children prop can also be a function — same pattern, cleaner JSX.

function Mouse({ children }) {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  /* ... */
  return children(pos);
}

<Mouse>
  {({ x, y }) => <p>{x}, {y}</p>}
</Mouse>

Higher-Order Components — The Idea

An HOC is a function that takes a component and returns a new component with extra props or behaviour. Used heavily in Redux's connect() and React Router's withRouter().

function withMouse(Component) {
  return function WithMouse(props) {
    const [pos, setPos] = useState({ x: 0, y: 0 });
    useEffect(() => {
      const handler = (e) => setPos({ x: e.clientX, y: e.clientY });
      window.addEventListener('mousemove', handler);
      return () => window.removeEventListener('mousemove', handler);
    }, []);
    return <Component {...props} mouse={pos} />;
  };
}

// Usage:
const Position = ({ mouse }) => <p>{mouse.x}, {mouse.y}</p>;
const EnhancedPosition = withMouse(Position);
<EnhancedPosition />

HOCs Compose by Wrapping

You can stack HOCs — but they form a 'wrapper hell' that's hard to debug.

// Multiple HOCs:
const Enhanced = withRouter(connect(mapState)(withTranslation()(MyComponent)));
// Equivalent in modern React:
// const Enhanced = MyComponent (reads from hooks: useRouter, useSelector, useTranslation)

Render Props vs HOC

Render props: more explicit, type-friendly, no naming collisions. HOCs: more declarative, lose static types on wrapped components without care, prop name collisions are possible.

Why Hooks Replaced Both

Custom hooks deliver the same goal with less ceremony: no wrapper components, no nested function arguments, no type gymnastics. Hooks are the idiomatic 2025 answer.

// Custom hook equivalent of useMouse:
function useMouse() {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  useEffect(() => {
    const handler = (e) => setPos({ x: e.clientX, y: e.clientY });
    window.addEventListener('mousemove', handler);
    return () => window.removeEventListener('mousemove', handler);
  }, []);
  return pos;
}

// Usage:
const { x, y } = useMouse();

When Render Props Still Win

For components that need to inject markup (not just state) — e.g. virtualised lists that render items at specific positions — render props are still the natural fit.

function VirtualList({ items, itemHeight, renderItem }) {
  const [scrollTop, setScrollTop] = useState(0);
  const start = Math.floor(scrollTop / itemHeight);
  const visible = items.slice(start, start + 20);
  return visible.map((item, i) => renderItem(item, start + i));
}

<VirtualList items={data} itemHeight={40} renderItem={(item, i) => (
  <Row key={i} data={item} />
)} />

HOC Best Practices (When Required)

If you must write an HOC: copy static methods (hoist-non-react-statics), forward refs (React.forwardRef), keep the displayName for DevTools.

Forwarding Refs in HOCs

HOCs hide refs by default — use forwardRef so consumers can still access the underlying component's ref.

function withLogger(Component) {
  const Wrapped = React.forwardRef((props, ref) => {
    console.log('rendering', Component.name);
    return <Component {...props} ref={ref} />;
  });
  Wrapped.displayName = `withLogger(${Component.name})`;
  return Wrapped;
}

Recognising Legacy Patterns

You'll meet HOCs/render props in: react-redux (older API), Apollo Client v2, react-router v5 (withRouter), Formik (Field), styled-components (withTheme). Refactor to hooks when these libraries' newer APIs allow.

Quick Check

What pattern have hooks largely replaced for sharing stateful logic between React components?

Recap: Render Props & HOCs

Render props: function-as-prop returning JSX, explicit and type-friendly. HOCs: function that wraps a component, used by older libraries (connect, withRouter). Custom hooks replaced both for state logic. Render props still win when you need to inject custom markup (virtualised lists). When writing HOCs: forwardRef, hoist statics, set displayName.

Frequently asked questions

Is the “Render Props and HOC Patterns” lesson free?

Yes — the full text of “Render Props and HOC Patterns” is free to read here on the web, and the Frontend Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Frontend Academy course, upgrade to CoddyKit PRO.

What will I learn in “Render Props and HOC Patterns”?

Pass a render function as a prop to inject UI, and wrap components in Higher-Order Components to inject behaviour without modifying the original. You practise Frontend Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Frontend Academy?

No prior experience is required. Frontend Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Render Props and HOC Patterns” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Frontend Academy lesson?

Yes. Every Frontend Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Compound Components with Context
  2. Render Props and HOC Patterns
  3. Portals for Modals and Tooltips
  4. Error Boundaries
← Back to Frontend Academy