← Back to React Course | Chapter 13: Advanced React & Architecture | Lesson 10 of 14

Common React Design Patterns

React design patterns are like well-known dance moves — once you recognize them, you can follow along in any routine, and other dancers instantly understand what you're doing.

Why Learn Named Patterns

Giving common code shapes names (like 'compound components' or 'render props') lets developers communicate design ideas quickly, and recognize familiar structures in unfamiliar codebases faster, rather than re-deriving how something works from scratch every time.

Note: This course covers each major pattern in its own dedicated tutorial — this one focuses on when and why to reach for which pattern.

Warning: Knowing a pattern's name isn't the goal by itself — the goal is recognizing which real problem it actually solves.

Example: Why Learn Named Patterns

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
// Recognizing the shape:
function useToggle(initial) {
  const [value, setValue] = React.useState(initial);
  return [value, () => setValue(v => !v)];
}
// "Oh, this is the custom hook pattern for shared stateful logic"
function App() {
  const [isOn] = useToggle(false);
  return <p>{isOn ? "On" : "Off"}</p>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>

Modern React Favors Hooks Over Older Patterns

Patterns like render props and higher-order components were the primary way to share logic between components before Hooks existed. Today, a custom hook usually accomplishes the same goal with less nesting and clearer code, so hooks are generally the first tool to reach for in new code.

Note: When you see a render-props or HOC pattern in an older codebase, it's often a good candidate to refactor into an equivalent custom hook.

Warning: Not every render-props/HOC usage needs to be immediately rewritten — refactor opportunistically, not as a disruptive, all-at-once rewrite.

Example: Modern React Favors Hooks Over Older Patterns

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
// Older pattern (HOC):
function withCounter(Wrapped) {
  return function(props) {
    const [count, setCount] = React.useState(0);
    return <Wrapped {...props} count={count} increment={() => setCount(count + 1)} />;
  };
}
// Modern equivalent (custom hook) is usually preferred for new code:
function useCounter() {
  const [count, setCount] = React.useState(0);
  return { count, increment: () => setCount(c => c + 1) };
}
ReactDOM.createRoot(document.getElementById('root')).render(<p>See dedicated pattern tutorials for full examples</p>);
  </script>
</body>
</html>

Choosing the Simplest Pattern That Fits

Every pattern trades some simplicity for some flexibility or reusability. Applying a complex pattern (like compound components) to a problem that only ever needs one straightforward implementation adds unnecessary abstraction — save it for when the flexibility is actually needed.

Note: A good question before reaching for an advanced pattern: 'will this actually be reused or varied, or am I just anticipating a need that may never come'?

Warning: Premature abstraction (building a flexible, pattern-based solution for a problem that doesn't need it yet) often makes code harder to understand than a simple, direct implementation would have been.

Example: Choosing the Simplest Pattern That Fits

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
// Simple, direct — fine if this is genuinely a one-off:
function SubmitButton() {
  return <button type="submit">Submit</button>;
}
// Only reach for a more elaborate pattern (compound components, render props)
// once you actually need multiple, meaningfully different variations.
ReactDOM.createRoot(document.getElementById('root')).render(<SubmitButton />);
  </script>
</body>
</html>
Common Mistakes
  1. Applying a pattern (like render props or HOCs) reflexively out of habit, when a simpler custom hook would do the same job more clearly.
  2. Not recognizing a familiar pattern in someone else's code, and rewriting it unnecessarily from scratch.
  3. Over-abstracting too early, building a flexible pattern for a case that only ever needs one simple, concrete implementation.
Chapter Summary
  • Common React patterns include compound components, render props, HOCs, custom hooks, and controlled/uncontrolled components.
  • Recognizing these patterns in existing code speeds up understanding unfamiliar codebases.
  • Modern React often favors custom hooks over older patterns like render props or HOCs for sharing logic.
  • Patterns are tools, not rules — use the simplest one that solves the actual problem at hand.
Browser Support

No React-version restriction — these are conventions and idioms, not specific APIs (except where noted, e.g. Context stable since React 16.3).

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.