cod;nncode. learn. thrive.

React Design Patterns 2023

Posted Dec 28, 2022

Reusing code in React: an introduction to render props and higher-order components

Reusing code in React: an introduction to render props and higher-order components

In React, it is common to use patterns like render props and higher-order components (HOCs) to reuse code and abstract away complex logic. These patterns can help to make your React code more modular, flexible, and maintainable.

Props

Render props is a pattern that involves passing a function as a prop to a functional component, which the component then calls to get the elements it should render. This allows the parent component to control what the child component renders, while still keeping the child component reusable.

Here's an example of a simple render prop functional component that shows a loading spinner while it is fetching data:

import React from "react";

const FetchData = ({ api, children }) => {
  const [data, setData] = React.useState(null);
  const [isLoading, setIsLoading] = React.useState(true);

  React.useEffect(() => {
    const fetchData = async () => {
      const data = await api.fetchData();
      setData(data);
      setIsLoading(false);
    };
    fetchData();
  }, [api]);

  return children({ data, isLoading });
};

This component has two state variables: data and isLoading. It also has a useEffect hook that calls an async function to retrieve data from an API when the component mounts. When the data is fetched, the hook updates the state variables to set isLoading to false and data to the fetched data.

The component's render method simply calls the function that was passed as the children prop, passing it the current state as an argument. This allows the parent component to control what the child component renders based on its state.

Here's an example of how the parent component might use the render prop component:

import React from "react";
import { FetchData } from "./FetchData";

const App = () => (
  <FetchData api={{ fetchData: () => Promise.resolve("Hello, world!") }}>
    {({ data, isLoading }) => {
      if (isLoading) {
        return <p>Loading...</p>;
      }
      return <p>{data}</p>;
    }}
  </FetchData>
);

In this example, the App component renders the FetchData component and passes it an API object as a prop. It also passes a function as the children prop, which is called with the current state of the FetchData component. If isLoading is true, the function returns a loading message. If isLoading is false, the function returns the fetched data.

Higher-Order Component (HOC)

Another common pattern in React is the higher-order component (HOC). An HOC is a function that takes a component as an argument and returns a new component that wraps the original component with additional functionality. HOCs are often used to abstract away complex logic or provide reusable behavior that can be shared across multiple components.

Here's an example of a simple HOC that adds a loading spinner to a functional component while it is fetching data:

import React from "react";

const withLoading = (WrappedComponent) => {
  return ({ isLoading, ...otherProps }) => {
    if (isLoading) {
      return <p>Loading...</p>;
    }
    return <WrappedComponent {...otherProps} />;
  };
};

This HOC is a function that takes a component as an argument and returns a new component that wraps the original component with additional functionality. The new component checks the value of the isLoading prop and, if it is true, displays a loading spinner. If isLoading is false, it renders the original component.

Here's an example of how the withLoading HOC might be used:

import React from "react";
import { withLoading } from "./withLoading";

const FetchData = ({ data }) => <p>{data}</p>;

const FetchDataWithLoading = withLoading(FetchData);

const App = () => <FetchDataWithLoading isLoading={true} data={null} />;

In this example, the FetchData component is a simple functional component that displays data passed to it as a prop. The withLoading HOC is a function that takes a component as an argument and returns a new component that wraps the original component with additional functionality.

To use the withLoading HOC, the FetchData component is passed as an argument to the withLoading function, which returns a new FetchDataWithLoading component. When the FetchDataWithLoading component is rendered with the isLoading prop set to true, it will display a loading spinner. If isLoading is false, it will render the FetchData component with the data prop passed to it.

Other Patterns

Component pattern

This pattern involves dividing a user interface into small, reusable components that can be easily managed and composed to build more complex user interfaces.

Container pattern

This pattern involves separating presentational components (that handle rendering) from container components (that handle data management and state). This helps to keep the components focused on their specific responsibilities and makes them easier to test and maintain.

State management pattern

This pattern involves managing the state of a React application in a centralized store, such as Redux or MobX, to make it easier to manage and maintain.

Unidirectional data flow pattern

This pattern involves following a strict unidirectional flow of data through a React application, where the top-level component passes data down to its children through props, and children pass data up to their parent through callbacks. This helps to keep the flow of data predictable and easy to understand.

Conclusion

Render props and HOCs are just two of the many patterns that are commonly used in React to reuse code and abstract away complex logic. These patterns can help to make your React code more modular, flexible, and maintainable, and are worth learning and using in your projects.

Further Resources

React 19: New Features List [Interview Ready]

Get interview-ready with our comprehensive guide on React 19, covering its groundbreaking advancements, new features, improved performance, and backward compatibility.

Read Here

Git How to Stash

The `git stash` command is used to stash changes in the working directory. This command saves changes in the stash stack, which can later be applied or popped.

Read Here

CRUD Operations in ReactJS Without API: GitHub Code Step-by-Step Example 2024

This article dives into implementing CRUD operations specifically in ReactJS without relying on an external API, providing a comprehensive step-by-step guide and a GitHub code example.

Read Here

Table Pagination tutorial in Reactjs using Server Side API data with Paginate, CSS example

Master the art of React pagination! Learn React.js pageable and paginate, style it with CSS, fetch data from APIs, and even implement server-side pagination with Node.js. Explore practical examples and level up your web development skills today.

Read Here

JavaScript Object Creation: Mastering Classes and Prototypes for Efficiency

Explore different methods of creating objects in JavaScript, with a focus on the 'class' keyword. Learn when to use each approach and the benefits they offer.

Read Here
Your feedback is our favorite notification! Share your thoughts about this page and make us smile.