React Design Patterns 2023
Posted Dec 28, 2022
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 HereGit 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 HereCRUD 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 HereTable 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 HereJavaScript 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