Headless UI Components: A Journey With High Order Components, Render Props, and Custom Hooks
By: Jennifer Fu
Tags: Reactjs, Programming, Nodejs, React, JavaScript

High Order Components

We have a component that prints out a simple UI:

For this article, the source code is verified in CodePen :

We want to make the text blue. This can be done by adding the style to line one or passing the style through line three. However, we want this style transformation logic to be reusable for other components too.

A high order component (HOC) is a good choice for this task. It’s a function that takes a component and returns a new component, with additional logic and behavior. It’s commonly defined as follows:

const EnhancedComponent = higherOrderComponent(WrappedComponent);

So, we create a HOC in the following code:

This HOC is named withColor (lines 1-8). It takes props and extracts out color if defined. Otherwise, it uses red as the default color (line 2). The rest props are passed down to the original component (line 5). It’s important to use composition, instead of mutating the original component.

This HOC wraps the original component by a div , styled with color (line 4), which is defined as blue at line 14.

Now we see the text blue:

You may be asking why we created TransformedComponent outside of App , instead directly mutating the original component in the render, as follows:

const App = () => {

const TransformedComponent = withColor(BaseComponent);

return <TransformedComponent value={1} color="blue"/>;

}

React’s diffing algorithm (also called reconciliation) uses component reference to determine whether it should update the existing subtree or throw it away and mount a new one. If the component returned from render is strictly equal to the component from the previous render, React recursively updates the subtree by diffing it with the new one. If they’re not equal, the previous subtree is completely unmounted.

If TransformedComponent is generated inside render, it has a new reference for each render, which would cause unnecessary unmounting.

If you have to put TransformedComponent inside render, the alternative way is to apply useMemo to keep the reference between renders.

withColor transforms the color. What if we also want to change the font style to be italic?

Another HOC is created to transform the font style:

This additional HOC is named withFontStyle (lines 1-8). It takes props and extracts out fontStyle if defined. Otherwise, it uses normal as the default fontStyle (line 2). The rest props are passed down to the original component (line 5).

This HOC wraps the original component by a div , styled with fontStyle (line 4), which is defined as italic at line 24.

Here we compose two HOCs at line 21.

What if we want to transform props in the original component, something like multiple of the original value?

Another HOC will do.

This new HOC is named withMultipleValue (lines 1 - 9). It takes props and extracts out factor if defined. Otherwise, it uses 1 as the default factor (line 2). A new value is calculated at line 3, which replaces the original value at line 6. newprops are passed down to the original component (line 8).

This HOC is applied at line 31, which times the factor, 5 , defined at line 36.

We compose three HOCs in lines 31-33. These lines look a little congested but they can be formatted like this if you have ramda installed:

import compose from "ramda"; const TransformedComponent = compose(

withMultipleValue,

withFontStyle,

withColor,

)(BaseComponent);

If you use Create React App, lodash is built-in and lines 31-33 can be written as: