In this tutorial, you will learn how to refactor components written within ReactJS into higher-order components (HOC). The aim of this article is to show you how you can write more reusable components. Using the HOC design pattern is desirable as it will help you to maximize reuse. This means writing less code 😎 Good code should avoid duplication, this is known as the DRY principle. Using HOCs will allow you to do just that. Let us take a common situation, calling a third-party API within your ReactJS application. If you are writing the boilerplate code to call an API, say using fetch()
, all over your app then you are breaking the rule of DRY. If you contained the code to call an API in a HOC you will get re-use!
⚠️The code in here is more geared for demonstrating principles, rather than production-ready code you can simply copy and paste.. be warned!
⚠️ This tutorial assumes that you have read How To Call An API In Your React Component.
Container and Presentational Pattern
When writing a ReactJS application, a good component design strategy to follow is the container and presentational pattern. This pattern may fancy and technical, however, it is not. If you need to write a component that has a lot of logic in it, instead of writing one component, try to break it into two. One that contains the logic and another component that does the rendering. Getting data from an API and rendering it, is a great example of where the container and presentational pattern can be applied. You can adopt the container and presentational pattern by creating a higher-order component. you get two design patterns in this article for one!
Higher-Order Components
Let's start with some code:
The component above is a wrapper. It contains no presentation code e.g, any JSX. Within the render()
method a simple loading message is displayed if the data is still loading. In production code, this would likely be a spinner component you call in. If the API has called the data the WrappedComponent
is rendered. WrappedComponent
is being passed in as a prop
. It is this passing in of a component and then rendering it with the render()
method which makes it a higher-order component. If you have come across the decorator pattern, a HOC follows this same philosophy. This is where the two design patterns that I have mentioned differ. The container/presentation pattern is about where the logic and the JSX live. The component above is the container as it contains the logic. The WrappedComponent
would be a presentation component.
The specific higher order part of this design is that WrappedComponent
is passed in and then the component calls it. By following these two patterns we have made simpler components which can also be re-used. Instead of writing all our code in one massive component, we've abstracted all the code to call an API into withData
. The component uses currying to pass in two arguments, the URL for the API and a component to wrap it. We use currying to make the calling code a little simpler (we'll get back to this later). In componentWillMount()
, fetch is used to get the data from the passed URL property. On a successful response, a property in a state called isFetching
is set to false. When isFetching
is changed a re-paint will be triggered, as isFetching
is now false the render() method will render the child component and
WrappedComponentwill be rendered.
WrappedComponent` will be rendered with all the props and state the wrapper got created with. This is a classic example of functional programming techniques in action!
To render some HTML on the page, a second presentation component needs to be written. To display our data in a simple list, we could write something like this:
We now have a very simple UI component. It has no clue to the data it uses and it should not care. This component is also a stateless component, which simplifies our code. To render the complete HTML, we now write:
As I'm hoping you can now appreciate, we have simplified our codebase a lot. We've created a component 'withData' we can re-use all over our codebase. Whenever we need to call an API we can use this component. We've also created a super simple, stateless presentation component to render out the list. As an added benefit, the component is now really simple to test, meaning it can also be more easily re-used. The original component I created can be seen in How To Call An API In Your React Component. Using these patterns on this component means our two components are simpler. If you consistently apply this approach, you will end up with lots of smaller reusable components, you will get more re-use and your components will become a lot easier to test. All in all.. a big win! Happy Coding 🤘