garytalmes.com

Take Your React Code to a New Level with Higher Order Components

One of the great strengths of React is that its componenyt-based architecture allows for some pretty amazing, and powerful, rendering patterns. When fully understood, these patterns can take your development to a new level. One of the most powerful, and often least understood, of these patterns are Higher Order Components (HOCs).

An HOC is, simply put, a function that receives a React component as an argument, and then returns a new, modified component which wraps around the original one. It's a way of dynamically injecting new functionality into a component without modifyiing the original. Thus you can still use the original component in its primary "mode", or you can use it in a modified mode which provides additional functionality.

Ok, let's work with an example:

I'm building a set of form components with specific UI settings and styles. For the purpose of this example, we'll focus on just one of them, the Input component. This component will generate an <input> element with specfic styling and settings. It might look something like this (Typescript omitted for brevity):

Loading...

This component isn't fully defined, but I think you get the idea. Notice that the component will receive its value via props -- this is ideal since it allows the component to be decoupled easily and used in any part of my app.

But because this component will be part of a small suite of related components, I'd like them all to share some data and settings. For that, I'd like to set up context.

Context is great because it allows for data to be shared throughout an app, but it has one potential drawback: it creates a dependency on the context itself. In other words, if my Input component is referencing context for some of its data, then I can't use this Input component elsewhere without also bringing the context apparatus with it. This limits the re-usabiity of my component. What if I sometimes just need an isolated Input?

That's where HOCs come in.

Let's assume I have create a file called FormContext, and a hook for it called useFormContext. I want my Input component to be able to make use of that useFormContext hook, but ONLY in specific cases. Other times, I want the Input to receive all data via props.

First, lets' build the HOC itself. HOCs typically begin with the word "with", much in the same way that hooks begin with "use". I'll put the code shown below in the same file as the Input component itself, although it could be placed anywhere. Let's look at shell first.

Loading...

Here we simply create the scaffolding for the HOC. Notice that it takes in a component as an argument. We can name this component whatever we want as it is only a variable referencing the real component that will be passed in. We'll use the name WrappedComponent. In other words, we are accepting as a prop a component, and we will wrap new functionality around that component. Let's do that now.

Loading...

You'll see that first we reference the useFormContext hook, and destructure from it the elements we need. We are getting the form data itself, the setter for that data, and the error state, all from context.

Now we return the WrappedComponent (which will be our Input component), but now we are passing in the values from the context as props.

What makes this pattern so powerful is that the original Input component is undisturbed. It receives all its data via props, all the time,. But the HOC gives us the ability to change how those prop values are generated.

The final step is to create a new component which can be called when we want to "bundle" the HOC with the Input. This is simple:

Loading...

We now have a new component, InputWithCtx, which we can use anytime we want to take adantage of context; but we can continue to use the original Input as well. The original Input maintains full control over appearance and functionality, but the HOC allows us to inject additional data and capabilities.

One final note, with proper planning, HOCs themselves can be re-usable, and can be applied across multiple components. You end up with a much more dyamic, extensible architecture without any duplication of code.

Author: Gary T Almes

I am the developer and owner of this web site. I've been working in the web development space for 35+ years and have experience in just about all phases of any development operation. I've owned my own web dev shop, been a senior level product and team manager, served as a senior developer, and I currently also teach MERN-stack web development in partnership with major universities. I'm available for occasional and regular development, management, or consulting needs.