React | Design Patterns
Design patterns are the templates which provides solution to common software development problems.
In React, they are many methods to solve the problems tackled by React developers.
As the React API grow, new patterns come out, and developers often advise them over previous patterns.
In this article, we will go through some of the useful React design patterns in.
React components design patterns:
- HOC Pattern (Higher Order Component Pattern)
- Contianer and Presentational Components Pattern
- Provider Pattern
- Hooks Pattern
Let get started and understand one by one :-)
1. HOC Pattern ( Higher Order Component Pattern )
This pattern is an advanced pattern and alternatively called as Decorator Pattern. It is used for reusing component logic across our application.
A high-order component is nothing but JavaScript higher-order function, they are pure functions with no side effects.
Example:
// Take in a component as argument WrappedComponent
function withName(WrappedComponent) {
// And return a new anonymous component
return class extends React.Component {
render() {
return <WrappedComponent name="React" {...this.props} />
}
}
}const Hello = ({ name }) => <h1>Hello {name}!</h1>const HelloReact = withNameReact(Hello);
// No need to send in the name prop, it is already sent in
// by the HOC. It will output Hello React!<HelloReact />
2. Contianer and Presentational Components Pattern
In this Pattern components are divided into:
- Container Components
- Presentational Components
Container components:
Container components are in charge of how things work. They are usually class components that contain required lifecycle methods and Presentational components. It is also where the data fetching happens and most of your main logic is written.
Presentational Components:
These are components that are in charge of how the UI looks. They don’t have any possession with any part of the app and are just used to display data or you can call this as dumb components, because these components do not own any logic that are related to app or to rendering. Just display what you give to them.
Example for Container Components:
class Movies extends React.Component {
state = {
movieList: []
};
componentDidMount() {
this.MoviesList(); // Data Fetching
}
render() {
return <MovieList movieList={movieList}/>;
// ... jsx code with presentation component
}
}
Example for Presentational Components:
const MovieList= ({Movies}) => {
return (
<ul>
{Movies.map((movie) => (
<li key={movie.id}>
{movie.name}
</li>
))}
</ul>
);
};
3. Provider Pattern
React developers every day faces one of the major problem is Props drilling. Props drilling in which data is passed down to different children components until it gets to the component where the prop is needed.
This is plot is not a problem, until it becomes a pain when the components which doesn’t need the props share the data.
This is where the Provide Pattern comes to help. The Provider pattern helps us to store/keep the data in a one location, e.g. React Context State/Object and the Redux store.
The Context Provider/Store can then send this data to any component that needs it directly without Props drilling.
For example: Take a theme logic like dark mode / light mode, to use this you need to pass the theme object to unrelated components to reach the particular component which uses the theme object. Because of this if any change happens to the theme object all the unrelated components will get triggered and re-renders which affects the performance of the app. To avoid this we can use is Provider Pattern.
Example:
const ThemeContext = React.createContext('dark');class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we are passing "dark" as the current value.
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
// A component in the middle doesn't have to// pass the theme down explicitly anymore.function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "light". static contextType = ThemeContext; render() {
return <Button theme={this.context} />;
}
}
4. Hooks Pattern
React 16.8 as introduced React Hooks and have completely transformed how we code our components.
Hooks API Provides super powers like state, context, refs and lifecycle to simple React Functional Components and make them special.
Because of this developers now a days don’t use class components anymore, why ? you will all the class components features in functional components because of Hooks API. The result of this functional components are not dumb anymore :-).
Anyway pattern like the container and presentational component allow us to separate concerns, containers frequently result in “huge components”: components with a huge logic split across several lifecycle methods. And big components can be hard to read and maintain.
Since containers are written as class components, they are not easily controlled. And when working with containers, we are also faced with other class-related problems such as autobinding and working the this
keyword.
Now with the functional components we can access all the class related features, the Hooks patterns solve the class-related problems mentioned above.
As pure JavaScript functions, functional components are controllable and eliminate the nuisance of working with this
keyword.
Example:
import React, { useState, useEffect } from "react";function UserProfile({ id }) {
const [isloading, setIsLoading] = useState(false);
const [user, setUser] = useState({});
useEffect(() => {
updateProfile(id);
subscribeToOnlineStatus(id);
return () => {
unSubscribeToOnlineStatus(id);
};
}, [id]);
const subscribeToOnlineStatus = () => {
// subscribe logic
};
const unSubscribeToOnlineStatus = () => {
// unsubscribe logic
};
const fetchUser = (id) => {
// fetch user logic here
};
const updateProfile = async (id) => {
setIsLoading(true);
// fetch user data
await fetchUser(id);
setIsLoading(false);
};
return; // ... jsx logic
}
export default UserProfile;
Hope this article help developers to solve common software development problems.
Help me to learn if you have any other React Design Patterns. Please add it in the comments.
Please hit 👏 button below as many times as possible to show your support!
Thanks for the read. Cheers!!!.
You are Awesome !
Sharing is Caring. So Share as much possible ;-).