React Higher Order Components
This tutorial is intended for advanced users who want to take advantage of the HOC pattern. If you’re new to React, you should probably start by reading the documentation.
A Higher Order Component (HOC) is a design pattern in React that allows a component to be wrapped by another component in order to extend or modify its behavior. HOCs are a powerful tool for reusing code and adding additional functionality to a component without modifying the original component.
In another word, A higher-order component (HOC) is a function that takes a component and returns a new component. HOCs are used to reuse code, add additional functionality to a component, or modify a component’s behavior. They are an advanced pattern in React and are not necessary for creating basic components.
Certainly! Higher-order components are a pattern in React that allows you to reuse code and extend the functionality of existing components. They are created by writing a function that takes a component as an argument and returns a new component. HOCs can be used for a variety of purposes, such as adding additional props to a component, altering the behavior of a component, or providing access to React’s context object.
One of the key benefits of using HOCs in React is that they allow you to reuse code and add additional functionality to a component without modifying the original component. This makes your code more maintainable and easier to update because you can change the behavior of multiple components by updating a single HOC.
Another benefit of HOCs is that they make it easier to test your components because they allow you to separate the behavior and functionality of a component into smaller, more modular pieces. This makes it easier to test each piece of functionality individually and to verify that the HOC and the wrapped component are working together properly.
React Hooks vs HOCs
React Hooks and higher-order components (HOCs) are two different patterns for reusing component logic in React.
React Hooks are a new feature in React 16.8 that allows you to use state and other React features without writing a class. This makes it easier to share logic between components and can make your code easier to read and understand.
Higher-order components, on the other hand, are a pattern that involves creating a new component that wraps an existing component in order to add additional functionality. This is often used for adding behavior such as authentication or theme management to a component.
React Hooks provide a more direct and simple way to reuse component logic, while higher order components are a more flexible and powerful pattern for extending a component’s behavior. It’s up to you to choose the approach that works best for your project.
What can I do with HOCs?
There are many ways you can use higher-order components in your React applications. Here are a few examples:
- Code reuse: You can use HOCs to extract common functionality from multiple components and reuse it in different parts of your app. This can help you avoid writing the same code multiple times and keep your components modular and easy to maintain.
- Props manipulation: HOCs can be used to add additional props to a component or modify the props that it receives from its parent. This can be useful for providing data or behavior that a component needs, but that its parent does not have.
- State abstraction: HOCs can be used to manage the state in a way that is decoupled from the components that use the state. This can help you keep your components pure and avoid dealing with complex state management logic.
- Render prop patterns: HOCs can be used to implement the render prop pattern, where a component exposes a function prop that allows its children to render different parts of the component. This can be useful for creating reusable components that can be customized by the components that use them.
We’ll go over these items in more detail later, but first, we’ll look at how to implement HOCs, because implementation both allows and limits what you can do with a HOC.
HOC factory implementations
A higher-order component factory is a function that returns a higher-order component. This can be useful when you want to create multiple HOCs that have the same basic structure, but that are customized for different purposes. Here is an example of a HOC factory that takes a prop name and a default value for that prop, and returns a HOC that adds the prop to a component with the specified default value:
const withDefaultProp = (propName, defaultValue) => (Component) =>
(props) => (
<Component {...props} {...{ [propName]: defaultValue }} />
);
To use this HOC factory, you would call it with the prop name and default value that you want, and then pass the resulting HOC a component to wrap. Here is an example of using this HOC factory to create a HOC that adds a color prop with a default value of red:
const withColor = withDefaultProp(’color’, ’red’);
You could then use the withColor HOC to wrap a component and add the color prop to it:
const MyButton = withColor(Button);
// This would render a ‘Button‘ component with a ‘color‘ prop set to
‘red‘
<MyButton>Click me!</MyButton>
This is just one example of how you can use a HOC factory to create HOCs. You can create HOC factories for any type of HOC that you want to create, and customize them as needed for your specific use case.
Props Proxy
In terms of props, a HOC can act as a props proxy, allowing you to pass additional props to the wrapped component. For example, if you have a HOC called withFoo that wraps a component MyComponent, you can pass a prop foo to withFoo and it will be passed to MyComponent as a prop. This is useful for providing additional information to the wrapped component without having to modify the original component.
Here is an example of a HOC factory that creates a HOC that acts as a props proxy:
function createPropsProxyHOC(propName) {
return function (WrappedComponent) {
return function (props) {
return <WrappedComponent {...props} {...{ [propName]:
someValue }} />;
}
}
}
In this example, the HOC factory createPropsProxyHOC takes a propName argument and returns a HOC that adds a prop with the specified name and a value of someValue to the wrapped component. You can use this HOC like this:
const MyComponentWithFoo = createPropsProxyHOC(’foo’)(MyComponent);
Now you can use MyComponentWithFoo in your application, and it will pass the prop foo with a value of someValue to MyComponent. This allows you to add additional functionality to MyComponent without modifying the original component.
What can be done with Props Proxy?
A props proxy is a way to add additional props to a component without modifying the original component. This can be useful for providing additional information to the wrapped component or for extending the functionality of the original component. Here are some examples of what you can do with a props proxy:
- Provide additional data to the wrapped component: You can use a props proxy to pass data from a higher-level component to a lower-level component without modifying the lower-level component. This allows you to keep the lower-level component reusable and independent from the higher-level component.
- Extend the functionality of the wrapped component: You can use a props proxy to add additional methods or behavior to a wrapped component. For example, you could add a method that handles a specific event or performs a specific action. This allows you to extend the functionality of the original component without modifying the original code.
- Modify the behavior of the wrapped component: You can use a props proxy to modify the behavior of the wrapped component. For example, you could override the render method of the wrapped component to change how it is rendered. This allows you to modify the behavior of the original component without modifying the original code.
Overall, a props proxy allows you to add additional functionality to a component without modifying the original component, making it a powerful tool for extending and modifying the behavior of existing components.
Manipulating props
A Higher Order Component (HOC) in React is a function that takes a component and returns a new component with additional functionality. HOCs are a pattern in React for reusing component logic.
When you use a HOC, you can manipulate the props of the wrapped component in a number of ways. Here are some examples of how you can manipulate props in a HOC:
- Pass additional props to the wrapped component: A HOC can act as a props proxy, allowing you to pass additional props to the wrapped component. For example, if you have a HOC called withFoo that wraps a component MyComponent, you can pass a prop foo to withFoo and it will be passed to MyComponent as a prop. This is useful for providing additional information to the wrapped component without having to modify the original component.
- Modify the props of the wrapped component: A HOC can modify the props of the wrapped component before passing them to the wrapped component. For example, you could use a HOC to transform the props of the wrapped component or to add or remove props from the wrapped component. This allows you to modify the behavior of the wrapped component without modifying the original code.
- Pass down modified props to child components: A HOC can pass down modified props to the child components of the wrapped component. For example, you could use a HOC to transform the props of the wrapped component, and then pass the transformed props to the child components of the wrapped component. This allows you to modify the behavior of the child components without modifying the original code.
Manipulating props in a HOC allows you to add additional functionality to a wrapped component, and to modify the behavior of the wrapped component and its child components without modifying the original code. This is a powerful tool for extending and modifying the behavior of existing components.
Accessing the instance via Refs
It is possible to access the instance of the wrapped component from within a HOC, but this is not recommended as it breaks the encapsulation of the component. In general, a HOC should not modify the internal state or behavior of the wrapped component, and accessing the instance of the wrapped component via refs is a way to do this.
Instead of accessing the instance of the wrapped component, it is recommended to use props and state to communicate between the HOC and the wrapped component. This allows you to add additional functionality to the wrapped component without breaking its encapsulation.
Here is an example of a HOC that uses refs to access the instance of the wrapped component:
function withFoo(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
this.wrappedComponent.someMethod();
}
render() {
return ( <
WrappedComponent ref = {
(c) => this.wrappedComponent = c
} {
...this.props
}
/>
);
}
}
}
In this example, the HOC withFoo uses the ref attribute to create a reference to the instance of the wrapped component. It then calls a method on the wrapped component instance in the componentDidMount lifecycle method.
As mentioned earlier, this is not a recommended approach and there are better ways to add additional functionality to a wrapped component without breaking its encapsulation. It is generally better to use props and state to communicate between the HOC and the wrapped component.
State abstraction
In React, components can have state, which is an object that contains data specific to that component. This state can be used to render dynamic information in the component’s render method. However, managing state directly in a component can become unwieldy as the component grows in complexity.
One way to manage state in a more scalable and maintainable way is to use a HOC to abstract the state logic into a separate component. This HOC can then manage the state and pass it down to the wrapped component as props.
For example, suppose we have a component called MyComponent that displays a list of items. The component has state that contains the items to display in the list. We can create a HOC called withState that manages the state for this component and passes the items down as props.
Here is an example of how withState could be implemented:
// withState.js
import React from’ react’;
const withState = WrappedComponent => {
return class extends React.Component {
constructor(props) {
super(props);
// Initialize the state with an empty array of items
this.state = {
items: []
};
}
// Method to add an item to the state
addItem = item => {
this.setState(prevState => ({
items: [...prevState.items, item]
}));
}
render() {
// Pass the state down as props to the wrapped component
return < WrappedComponent items = {
this.state.items
}
addItem = {
this.addItem
} {
...this.props
}
/>;
}
}
};
export default withState;
We can then use the withState HOC to wrap MyComponent and abstract the state logic into the HOC:
// MyComponent.js
import React from ’react’;
import withState from ’./withState’;
class MyComponent extends React.Component {
render() {
// Use the items and addItem props that were passed down from the
HOC
const { items, addItem } = this.props;
return (
<div>
<button onClick={() => addItem(’item 1’)}>Add item</button>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
}
export default withState(MyComponent);
In this example, MyComponent no longer needs to manage its own state. Instead, it receives the items and addItem props from the withState HOC, which handle the state logic. This makes the code more modular and easier to maintain.
Inheritance Inversion
Inheritance inversion (also called wrapper inheritance) is a pattern that can be used in conjunction with higher-order components (HOCs) in React to improve code reuse and readability.
In React, a HOC is a function that takes a component and returns a new component. This new component is often called the “wrapped” or “inverted” component. HOCs are useful for abstracting common logic, such as managing state or handling data fetching, into a separate component that can be shared among multiple other components.
In the inheritance inversion pattern, the HOC is used to create a new component that wraps the original component and inverts the traditional inheritance hierarchy. This means that the original component becomes the base class, and the HOC becomes the derived class. For example, suppose we have a component called BaseComponent that contains some common logic that we want to reuse in other components. We can create a HOC called withCommonLogic that wraps BaseComponent and inverts the inheritance hierarchy:
// withCommonLogic.js
import React from’ react’;
const withCommonLogic = WrappedComponent => {
return class extends WrappedComponent {
// Implement common logic here
render() {
return super.render();
}
}
};
export default withCommonLogic;
We can then use the withCommonLogic HOC to wrap other components that need to reuse the common logic from BaseComponent:
// OtherComponent.js
import React from’ react’;
import withCommonLogic from’. / withCommonLogic’;
class OtherComponent extends React.Component {
// Other component logic here
render() {
return (
<div> {
/* Use common logic from BaseComponent here */ }
</div>
);
}
}
export default withCommonLogic(OtherComponent);
In this example, OtherComponent is wrapped by the withCommonLogic HOC, which inverts the inheritance hierarchy. This allows OtherComponent to inherit the common logic from BaseComponent without having to duplicate the code.
In summary, inheritance inversion is a pattern that can be used with HOCs in React to improve code reuse and readability. It involves using a HOC to create a new component that wraps the original component and inverts the inheritance hierarchy, allowing the original component to become the base class and the HOC to become the derived class.
What can you do with Inheritance Inversion?
You might use inheritance inversion with HOCs in React when you want to add the same props or functionality to multiple components without repeating the same code in each component. This can help you to keep your code DRY (Don’t Repeat Yourself) and make it easier to manage and maintain.
Here are some examples of when you might use inheritance inversion with HOCs in React:
- You want to add the same props, such as a user’s name or authentication status, to multiple components.
- You want to add the same event handlers, such as an onClick handler, to multiple components.
- You want to add the same styling, such as a default font or color scheme, to multiple components.
Inheritance inversion can also be a useful pattern to consider when you want to reuse code logic in your React application. It can help you to keep your code DRY and make it easier to manage and maintain.
Render Highjacking
Render highjacking is a powerful technique that can allow you to add additional functionality to a base component, but it can also make your code more difficult to understand and maintain. As such, it should be used with caution and only when it is the best solution for the problem at hand.
One common use case for this pattern is to abstract away complex or repeated rendering logic. For example, if you have a component that needs to render the same set of child components in different ways depending on certain conditions, you can use a HOC to handle the conditional rendering and simplify the code in the original component.
Another use case for HOC render-highjacking is to provide additional rendering behavior or functionality to a wrapped component. For example, you could use a HOC to add animations to a component or to provide additional props to the wrapped component based on some external data.
Here is an example of how you might use render highjacking with HOCs in React:
// MyBaseComponent.js
import React from ’react’;
const MyBaseComponent = ({ name }) => (
<div>{name}</div>
);
export default MyBaseComponent;
// withName.js
import React from ’react’;
import MyBaseComponent from ’./MyBaseComponent’;
const withName = WrappedComponent => {
const WithName = props => {
const newProps = {
...props,
name: ’John Doe’
};
return (
<WrappedComponent {...newProps} />
);
};
return WithName;
};
export default withName;
// App.js
import React from ’react’;
import MyBaseComponent from ’./MyBaseComponent’;
import withName from ’./withName’;
const MyEnhancedComponent = withName(MyBaseComponent);
const App = () => (
<MyEnhancedComponent />
);
In this example, the withName HOC takes the MyBaseComponent as an argument and returns a new component that has the name prop added to it. This is accomplished by replacing the MyBaseComponent’s original render method with a new one that adds the name prop to the props object.
Render Highjack with Props Proxy
It is possible to use React Higher-Order Components (HOCs) with props proxy, but it is not necessarily the best approach in all cases. HOCs and props proxy are both patterns that can be used to reuse code and behavior across multiple components, but they have some key differences in how they work and when they are appropriate to use.
One main difference between HOCs and props proxy is that HOCs wrap a component and return a new, enhanced component, while props proxy injects additional props into the wrapped component directly. This means that when using HOCs, you need to use the enhanced component that is returned by the HOC, rather than the original component, in order to access the additional behavior or functionality provided by the HOC.
On the other hand, props proxy allows you to keep using the original component, but with additional props injected into it. This can be useful if you want to add new props to a component without changing how it is used or referenced elsewhere in your code.
Naming
When naming a React Higher-Order Component (HOC), it is important to choose a name that accurately describes the behavior or functionality that the HOC provides. This will make it easier for other developers who use your HOC to understand what it does, and will also make it easier for you to maintain and work with the HOC in the future.
One common approach to naming a HOC is to use the name of the original component that the HOC wraps, followed by the suffix “With” and a descriptive phrase that indicates the additional behavior or functionality provided by the HOC. For example, if you have a HOC that adds a loading indicator to a component, you could name it WithLoadingIndicator.
Another approach is to use a more general name that describes the overall purpose or role of the HOC. For example, if you have a HOC that provides additional props to a wrapped component based on some external data, you could name it WithPropsFromExternalData.
The most important thing is to choose a name that is descriptive, meaningful, and easy to understand. This will help other developers who use your HOC, and will also make it easier for you to maintain and work with the HOC in the future.
Best Practices using HOC
Here are a few best practices for using Higher Order Components (HOCs) in React:
- Use HOCs to add additional behavior or functionality to a component but avoid using HOCs to add styling or layout to a component. Instead, use CSS or other styling techniques to add styling to a component, and use the React style prop or className prop to apply styles to a component.
- Avoid deeply nested HOCs, as they can make it difficult to understand the behavior and functionality of a component. Instead, try to keep your HOCs shallow, and use multiple HOCs to add different types of functionality to a component, rather than using a single HOC with multiple layers of nesting.
- Use the displayName property to give your HOCs and wrapped components more descriptive names, which can make it easier to debug and understand the behavior of your components. For example, you could set the displayName property of a HOC to withData and the displayName property of the wrapped component to MyComponent.
- Use the forwardRef API to pass a ref to the wrapped component, which can make it easier to access the wrapped component and its methods from the parent component. This is especially useful if you need to access the wrapped component’s methods in order to trigger a specific behavior or action.
- Avoid modifying the original component when creating a HOC. Instead, use React.cloneElement method to create a new, modified version of the original component, and return that new component from the HOC. This ensures that the original component remains unmodified, and can be used elsewhere in your application without any unexpected behavior.
Overall, following these best practices can help you to write clean, maintainable code when using HOCs in React.
We’re here to help!
If you have any further questions or want to clarify any existing topics of discussion, feel free to reach out over Email, Chat, or Call. Got a project for us? We’re available 24/7.
+1 (704) 325–9288
contact@direct-software-solutions.com
Find us on the web:
Website — Facebook — Instagram — YouTube — LinkedIn — Twitter