Lucas
Lucas

guide

Common Patterns in React: A Design Perspective

15 min read

Common Patterns in React: A Design Perspective

Overview

Explore common design patterns in React applications and understand how they contribute to building robust and maintainable code.

ReactDesign PatternsArchitecture

Design patterns provide reusable solutions to common problems in React development. Understanding these patterns will help you write more maintainable, scalable, and elegant code. This comprehensive guide covers essential React design patterns, when to use them, and how to implement them effectively.

Why Design Patterns Matter

Design patterns solve recurring problems in software design. In React, they help you:

  • Write more maintainable code
  • Improve code reusability
  • Make code easier to understand
  • Follow established best practices
  • Build scalable applications

Container/Presentational Pattern

The Container/Presentational pattern separates components into two categories: containers that handle logic and presentational components that handle UI.

Understanding the Pattern

This pattern promotes separation of concerns:

  • Presentational Components: Focus on how things look
  • Container Components: Focus on how things work

Presentational Components

Presentational components are pure functions that receive data and callbacks via props:

Container Components

Container components handle state, data fetching, and business logic:

Benefits

  • Clear separation of concerns
  • Easier to test presentational components
  • Better reusability
  • Easier to understand component responsibilities

Modern Approach

With Hooks, this pattern is less necessary, but still valuable for complex components. You can use custom hooks to extract logic while keeping components focused.

Higher-Order Components (HOCs)

HOCs are functions that take a component and return a new component with additional functionality. They're useful for cross-cutting concerns.

Basic HOC Pattern

HOCs wrap components to add functionality:

Common HOC Use Cases

HOCs are useful for:

  • Authentication and authorization
  • Data fetching and loading states
  • Error handling
  • Logging and analytics
  • Styling and theming

HOC with Props

HOCs can accept configuration:

Composing HOCs

You can compose multiple HOCs together:

HOCs vs Hooks

Custom Hooks often replace HOCs in modern React, but HOCs are still useful for certain scenarios, especially when you need to conditionally render components.

Render Props Pattern

The Render Props pattern shares code between components using a prop whose value is a function that returns React elements.

Basic Render Props

Components accept a function as a prop that determines what to render:

Children as Function

A common variation uses children as a function:

When to Use Render Props

Render Props are useful when:

  • You need to share stateful logic
  • You want flexible rendering
  • You need to pass data to children

Render Props vs Hooks

Custom Hooks often replace Render Props, but Render Props are still useful when you need more control over rendering or when working with class components.

Custom Hooks Pattern

Custom Hooks are the modern way to extract and share component logic. They're functions that start with "use" and can call other Hooks.

Basic Custom Hook

Extract component logic into reusable hooks:

Custom Hook Benefits

Custom Hooks provide:

  • Logic reusability
  • Cleaner components
  • Easier testing
  • Better organization

Common Custom Hook Patterns

Popular custom hook patterns include:

  • Data fetching hooks
  • Form handling hooks
  • Local storage hooks
  • Window size hooks
  • Debounce/throttle hooks

Compound Components Pattern

Compound Components are components that work together as a cohesive unit, sharing implicit state while maintaining a flexible API.

Basic Compound Components

Create components that work together:

Compound Components with Context

Use Context to share state between compound components:

When to Use Compound Components

Use compound components when:

  • Components are closely related
  • You want flexible composition
  • You need implicit state sharing
  • You want a clean API

Examples

Common examples include:

  • Tabs components
  • Accordion components
  • Form components
  • Modal components

Provider Pattern

The Provider pattern uses React Context to provide data to multiple components without prop drilling.

Basic Provider Pattern

Create a Provider component that wraps your app:

Custom Provider Hook

Create a custom hook for consuming the context:

Multiple Providers

You can nest multiple providers for different concerns:

When to Use Providers

Use the Provider pattern for:

  • Theme management
  • User authentication
  • Language/localization
  • Global UI state
  • Feature flags

Controlled vs Uncontrolled Components

Understanding when to use controlled or uncontrolled components is crucial for form handling.

Controlled Components

Controlled components have their state controlled by React:

Uncontrolled Components

Uncontrolled components use refs to access DOM values:

When to Use Each

Use controlled components for most cases. Use uncontrolled components when you need to integrate with non-React code or for simple forms.

Lifting State Up

Lifting state up means moving state to a common ancestor component when multiple components need to share it.

When to Lift State

Lift state when:

  • Multiple components need the same state
  • Components need to stay in sync
  • State needs to be shared

Alternative: Context or State Management

For deeply nested state sharing, consider Context API or state management libraries instead of lifting state through many levels.

Composition over Configuration

Prefer composition (combining components) over configuration (passing many props).

Configuration Approach (Less Flexible)

Passing many props to configure behavior:

Composition Approach (More Flexible)

Using composition for flexibility:

When to Use Each Pattern

Choosing the right pattern depends on your specific use case:

  • Container/Presentational: Clear separation of concerns, complex components
  • HOCs: Cross-cutting concerns, conditional rendering
  • Render Props: Flexible rendering, sharing stateful logic
  • Custom Hooks: Reusable logic, modern React (preferred)
  • Compound Components: Related UI elements, flexible composition
  • Provider Pattern: Global state, avoiding prop drilling

Pattern Combinations

You can combine patterns for more complex scenarios:

  • Custom Hooks with Provider Pattern
  • Compound Components with Context
  • HOCs with Custom Hooks

Anti-Patterns to Avoid

Avoid these common mistakes:

  • Over-engineering simple problems
  • Using patterns unnecessarily
  • Mixing too many patterns
  • Not understanding when to use each pattern

Conclusion

Design patterns are tools in your React toolkit. Understanding these patterns helps you write better code, but don't over-engineer. Start simple and apply patterns when they solve real problems. Custom Hooks are often the modern solution, but other patterns still have their place. Choose the pattern that best fits your use case, and remember: the best pattern is the one that makes your code more maintainable and easier to understand.