React Patterns — Higher-Order Components
By: John Au-Yeung
Tags: JavaScript, Web Development, Software Development, Technology, Programming

Photo by Henry Be on Unsplash

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at how to compose React components.

Higher-Order Components

Higher-order components are components that accept other components as arguments and return them after modifying them.

A higher-order component looks like the following:

const HoC = Component => EnhancedComponent

We take in a component and return an enhanced one.

For instance, we can write:

const withClassName = Component => props => (

<Component {...props} className="foo" />

)

Then we can return a component that has a class name prop added to it.

Instead of using it directly, we write:

const ComponentWithClassName = withClassName(Component)

We always start our higher-order component with with so that we can tell them apart.

With higher-order components, we can create different ones that are similar to each other, but mostly the same.

Recompose

The Recompose package has various high-order components that we can use individually or in combination.

To install it, we can run:

npm install recompose --save

Then we can use it by writing:

import React from "react";

import { withState } from "recompose"; const enhance = withState("count", "setCount", 0);

const Counter = enhance(({ count, setCount }) => (

<div>

Count: {count}

<button onClick={() => setCount(n => n + 1)}>Increment</button>

</div>

)); export default function App() {

return <Counter />;

}

We created a Counter component with the withState function to hold the state instead of using the useState hook.

Then we pass our component into the enhance function so that we can get the props we need.

The state and function to set it are available as props.

This lets our state be used in multiple components.

There are many other functions we can use.

For instance, we can write:

import React from "react";

import { withProps, flattenProp, compose } from "recompose";

const enhance = compose(

withProps({

obj: { a: "a", b: "b" },

c: "c"

}),

flattenProp("obj")

); const Foo = enhance(({ a, b, c }) => (

<div>

{a} {b} {c}

</div>

)); export default function App() {

return <Foo />;

}

We called compose to combine multiple higher-order components into one.

We have withProps to pass in some props.

And we called flattenProp to flatten the nested obj prop.

Then to create Foo we pass in a component into the enhance function and show the values of the props.

Then we display Foo in App .

Function as Child

Functions can be passed in as a child prop of another component.

For instance, we write:

const FunctionAsChild = ({ children }) => children()

To use it, we can write:

import React from "react"; const FunctionAsChild = ({ children }) => children(); export default function App() {

return <FunctionAsChild>{() => <div>hello/div>}</FunctionAsChild>;

}

We passed in a function in between the tags so that it can be called in FunctionAsChild .

Also, we can pass in parameters. For instance, we can write:

import React from "react"; const Greeting = ({ children }) => children("james"); export default function App() {

return <Greeting>{name => <div>Hello, {name}!</div>}</Greeting>;

}

We have a Greeting component, we call children , which is what’s between the tags.

Then in App , we pass in a function that we call in Greeting .

This makes our function much more flexible.

Data Flow

React has unidirectional data flow.

It always flows from parent to child.

For a child to communicate with a parent, we must call a function that’s passed in from the parent to the child.

For instance, we can write:

import React from "react"; const Greeting = ({ greeter }) => greeter("james"); export default function App() {

return <Greeting greeter={name => <div>Hello, {name}!</div>} />;

}

We pass in a greeter prop, which is a function from App to Greeting , which we call in there to render the element it returns.

Photo by Alvan Nee on Unsplash

Conclusion

We can separate logic from the presentation with higher-order components.

They can have logic that is reused in multiple components.

There are also libraries that will help us separate the logic.

React has one-way data flow, so we always have to pass props from parent to child.

But child components can call functions passed from the parent.

JavaScript In Plain English

Did you know that we have four publications and a YouTube channel? Find them all at plainenglish.io and subscribe to our YouTube channel!