React Design Patterns
Anuradha Aggarwal

Anuradha Aggarwal @anuradha9712

About: Software Development Engineer II

Location:
New Delhi
Joined:
Oct 9, 2019

React Design Patterns

Publish Date: Jul 9 '23
188 21

Hello developers!! While developing apps in React, I'm sure you have come across different use cases which cannot be easy to solve using the same older approach.

Each use cases demand a different pattern to solve the problem in the most optimised way and also made our code more scalable.

React provides different design patterns to solve common problems. The list of commonly used design patterns in React are:

  • Presentational & Container Component

  • Higher Order Components

  • Render Props

  • Compound Components

  • Hooks

Let's explore them one by one.

🎯 1. Presentational & Container Component

Each component in React has two parts: One is logic to handle your data and the other is displaying data on screen.

This pattern helps separate concerns by splitting components into two categories. Container components handle the logic and state management, while Presentational components focus on rendering the UI based on the provided props.

export const DisplayList = ({ patientRecord }) => {
  return (
    <ul>
      {patientRecord.map((patient, id) => {
        return <li key={id}>{patient}</li>;
      })}
    </ul>
  );
};
Enter fullscreen mode Exit fullscreen mode

Container components, on the other hand, keep track of the internal states and data-fetching logic and handles business logic.

export const PatientComponent = () => {
  const [patientList, getPatientList] = React.useState([]);

  React.useEffect(() => {
    // Fetch data through an API and apply business logic
    (async () => {
      const response = await fetchPatientList();

      setPatientList([...response]);
    })()
  }, []);

  // provide data to presentational component to display
  return <DisplayList patientRecord={patientList} />; 
};
Enter fullscreen mode Exit fullscreen mode

The container component passes the state and any required callbacks as props to the presentational component. The presentational component is responsible for rendering the UI based on the provided props, without worrying about the data fetching or business logic.

🎯 2. Higher Order Components

HOCs take one component as an input and give a newly created component with additional functionalities as an output. It allows you to reuse component logic by wrapping components with additional functionality.

By using HOCs, we can easily add common functionality to multiple components without duplicating code.

import React from 'react';

function withLogging(WrappedComponent) {
  return function WithLogging(props) {
    React.useEffect(() => {
      console.log(`Component ${WrappedComponent.name} mounted`);
      return () => {
        console.log(`Component ${WrappedComponent.name} unmounted`);
      };
    }, []);

    return <WrappedComponent {...props} />;
  };
}

// Usage
const MyComponent = (props) => {
  return <div>My Component</div>;
};

const EnhancedComponent = withLogger(MyComponent);
Enter fullscreen mode Exit fullscreen mode

In the example above, withLogger is a HOC that takes a component (WrappedComponent) as input and returns a new component (WithLogger). The returned component logs a message to the console when it mounts and unmounts.

To use the HOC, we wrap our original component MyComponent with withLogger, creating a new component EnhancedComponent. The enhanced component has the same functionality as MyComponent, but it also includes the logging behaviour defined in the HOC.

🎯 3. Render props

In this pattern, a component receives a function as a prop and uses that function to render its content.

import React from 'react';

const MouseTracker = (props) => {
  const [position, setPosition] = React.useState({ x: 0, y: 0 });

  const handleMouseMove = (event) => {
    setPosition({ x: event.clientX, y: event.clientY });
  };

  return <div onMouseMove={handleMouseMove}>{props.renderPosition(position)}</div>;
};

// Usage
const DisplayMousePosition = () => (
  <MouseTracker
    renderPosition={({ x, y }) => (
      <div>
        Mouse position: {x}, {y}
      </div>
    )}
  />
);
Enter fullscreen mode Exit fullscreen mode

A prop like renderPosition is called a render prop because it is a prop that specifies how to render a piece of the user interface.

🎯 4. Compound Components

Compound components are a pattern used in React to create components that work together as a group, allowing users to customize and control the rendering of multiple related components.

It allows you to define a parent component that encapsulates the behaviour and state of child components, while still giving flexibility to users to determine the composition and appearance of the child components.

Let's consider a use case where you need to create a List component in React which looks something like an unordered list in native HTML or an Accordion component.

<List>
 <ListItem>1</ListItem>
 <ListItem>2</ListItem>  
 <ListItem>3</ListItem>
 <ListItem>4</ListItem> 
</List>
Enter fullscreen mode Exit fullscreen mode

Now in this scenario, we need some of the states of the List component to be transferred to its child component i.e. ListItem. It can be implemented either by using the context API or React.cloneElement API.

Let's explore how to develop the same scenario using Context API.

const ListContext = React.createContext();
const { Provider } = ListContext;

// Parent Component
export const List = (props) => {
  const { children, size } = props;

  const sharedProp = { size }

  return (
    <Provider value={sharedProp}>
      <ul>
        {children}
      </ul>  
    </Provider>
  )
}

// Child Component
export const ListItem = (props) => {
  const contextProp = React.useContext(ListContext);
  const { size } = contextProp;

  return (
   <li className={size === 'medium' ? bg-primary : bg-secondary}>
      {props.children}
   </li>
  )
}

// Usage
<List size='medium'>
 <ListItem>Item 1</ListItem>
 <ListItem>Item 2</ListItem>
 <ListItem>Item 3</ListItem>
</List>
Enter fullscreen mode Exit fullscreen mode

In the above example, React Context is created to share the prop size between the parent (<List>) and child (<ListItem>) components. Also, the user has the flexibility to provide custom content inside each list item.

🎯 5. Hooks

Hooks are introduced in React Functional component as a replacement for Class components. There are multiple hooks available to manage states and different lifecycle methods of React.

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <Button onClick={() => setCount(count + 1)}></Button>
  )
}
Enter fullscreen mode Exit fullscreen mode

We can also create custom hooks to solve our specific use case and code reusability.

You can read about the most commonly used built-in react hooks here.

🎯 Wrap Up!!

That's all for this article. Thank you for your time!! Let's connect to learn and grow together. LinkedIn Twitter Instagram

Buy-me-a-coffee

Comments 21 total

  • Julio Herrera
    Julio HerreraJul 10, 2023

    Amazing!

    • Hennry Smith
      Hennry SmithJul 19, 2024

      Great Design Patterns. I like them.

  • Amn3s1a2018
    Amn3s1a2018Jul 10, 2023

    From react components docs: "Class components are still supported by React, but we don’t recommend using them in new code."

  • George WL
    George WLJul 10, 2023

    Why are you making so much use of Class components?

    I believe they're seen as bad practice, no?

    • Dev Paul
      Dev PaulJul 11, 2023

      Not really bad practice per say. Just that their use are discouraged and instead functional components should be used.

      • Rense Bakker
        Rense BakkerJul 31, 2023

        Deprecated as per React 18 and the new React docs.

    • CitronBrick
      CitronBrickJul 13, 2023

      I don't believe that class components deserve the bad rep.

      • Andrew McCallum
        Andrew McCallumJul 14, 2023

        I'm a big fan of classes and object oriented programming but I don't think classes are a good use case for react components.

        Dan Abramov explains here how class components can lead to bugs which are avoided with functional components.
        overreacted.io/how-are-function-co...

        Furthermore, you can't use hooks in class components so you are limited to what libraries and other parts of your code base you can use if you mix and match between classes and functional components

  • Fabio
    FabioJul 11, 2023

    Lol I use all of them but never heard that they are called this way.

    • Ayush
      AyushJul 13, 2023

      Everyone uses all of these just they don't know

      • Rense Bakker
        Rense BakkerJul 31, 2023

        There's a difference between using a library that happens to still use class components and writing class components yourself though...

  • Erick Torres
    Erick TorresJul 12, 2023

    Few things to take into account:

    • It is not recommended using async functions in the useEffect callback, instead do something like:
    useEffect(() => {
      (async () => {
        const response = await fetch('....')
      })()
    }, []);
    
    Enter fullscreen mode Exit fullscreen mode
    • Instead of running this const { Provider } = ListContext; on every render, just move to outside of the component.
    const { Provider } = ListContext;
    
    export const Component = (props) => {
      return (
        <Provider value={...}>
              ......
        </Provider>
      )
    }
    
    Enter fullscreen mode Exit fullscreen mode
  • АнонимJul 12, 2023

    [hidden by post author]

  • Deyvson Aguiar
    Deyvson AguiarJul 13, 2023

    Thanks for article ,👏👏😃

  • Anuradha Aggarwal
    Anuradha AggarwalJul 13, 2023

    @just-another-girl-w3 I'm glad you find it useful!!😃

  • Brayan Paucar
    Brayan PaucarJul 14, 2023

    Great article , please checkout this website refactoring.guru/design-patterns and tell me what’s the difference between patterns with those that you mentioned

  • Panayiotis Georgiou
    Panayiotis GeorgiouJul 16, 2023

    THANKS A LOT!

  • cesar
    cesarAug 4, 2023

    Am I the only one that thinks that Presentational/Container pattern does the opposite of helping?

  • 8kigai
    8kigaiAug 14, 2023

    withLogging or withLogger ? I think you have a typo there.

Add comment