Sunday, August 30, 2020

React Children And Iteration Methods

 In this article, we’ll discuss and learn about the use case of iterating over React children and the ways to do it. In particular, we will deep dive into one of the utility methods, React.Children.toArray, that React gives us, which helps to iterate over the children in a way which ensures performance and determinism.

The most obvious and common prop that developers work with within React is the children prop. In the majority of cases, there is no need to understand how the children prop looks like. But in some cases, we want to inspect the children prop to maybe wrap each child in another element/component or to reorder or slice them. In those cases inspecting how the children prop looks like becomes essential.

In this article, we’ll look at a React utility React.Children.toArray which lets us prepare the children prop for inspection and iteration, some of its shortcomings and how to overcome them — through a small open-source package, to keep our React code function the way it is deterministically supposed to behave, keeping performance intact. If you know the basics of React and have at least an idea about what the children prop in React is, this article is for you.

While working with React, most of the time we do not touch the children prop any more than using it in React components directly.

function Parent({ children }) {
  return <div className="mt-10">{children}</div>;
}

But sometimes we have to iterate over the children prop so that we can enhance or change the children without having the user of the components explicitly do it themselves. One common use case is to pass the iteration index-related information to child components of a parent like so:

import { Children, cloneElement } from "react";

function Breadcrumbs({ children }) {
  const arrayChildren = Children.toArray(children);

  return (
    <ul
      style={{
        listStyle: "none",
        display: "flex",
      }}
    >
      {Children.map(arrayChildren, (child, index) => {
        const isLast = index === arrayChildren.length - 1;

        if (! isLast && ! child.props.link ) {
          throw new Error(
            `BreadcrumbItem child no. ${index + 1}
            should be passed a 'link' prop`
          )
        } 

        return (
          <>
            {child.props.link ? (
              <a
                href={child.props.link}
                style={{
                  display: "inline-block",
                  textDecoration: "none",
                }}
              >
                <div style={{ marginRight: "5px" }}>
                  {cloneElement(child, {
                    isLast,
                  })}
                </div>
              </a>
            ) : (
              <div style={{ marginRight: "5px" }}>
                {cloneElement(child, {
                  isLast,
                })}
              </div>
            )}
            {!isLast && (
              <div style={{ marginRight: "5px" }}>
                >
              </div>
            )}
          </>
        );
      })}
    </ul>
  );
}

function BreadcrumbItem({ isLast, children }) {
  return (
    <li
      style={{
        color: isLast ? "black" : "blue",
      }}
    >
      {children}
    </li>
  );
}

export default function App() {
  return (
    <Breadcrumbs>
      <BreadcrumbItem
        link="https://goibibo.com/"
      >
        Goibibo
      </BreadcrumbItem>

      <BreadcrumbItem
        link="https://goibibo.com/hotels/"
      >
        Hotels
      </BreadcrumbItem>

      <BreadcrumbItem>
       A Fancy Hotel Name
      </BreadcrumbItem>
    </Breadcrumbs>
  );
}

Take a look at the Codesandbox demo. Here we’re doing the following:

  1. We are using the React.Children.toArray method to ensure that the children prop is always an array. If we do not do that, doing children.length might blow because the children prop can be an object, an array, or even a function. Also, if we try to use the array .map method on children directly it might blow up.
  2. In the parent Breadcrumbs component we are iterating over its children by using the utility method React.Children.map.
  3. Because we have access to index inside the iterator function (second argument of callback function of React.Children.map) we are able to detect if the child is last-child or not.
  4. If it is the last child we clone the element and pass in the isLast prop to it so that the child can style itself based on it.
  5. If it is not the last child, we ensure that all those children which aren’t the last child have a link prop on them by throwing an error if they don’t. We clone the element as we did in step 4. and pass the isLast prop as we did before, but we also additionally wrap this cloned element in an anchor tag.

The user of Breadcrumbs and BreadcrumbItem doesn’t have to worry about which children should have links and how they should be styled. Inside the Breadcrumbs component, it automatically gets handled.

This pattern of implicitly passing in props and/or having state in the parent and passing the state and state changers down to the children as props is called the compound component pattern. You might be familiar with this pattern from React Router’s Switch component, which takes Route components as its children:

// example from react router docs
// https://reactrouter.com/web/api/Switch

import { Route, Switch } from "react-router";

let routes = (
  <Switch>
    <Route exact path="/">
      <Home />
    </Route>
    <Route path="/about">
      <About />
    </Route>
    <Route path="/:user">
      <User />
    </Route>
    <Route>
      <NoMatch />
    </Route>
  </Switch>
);

Now that we have established that there are needs where we have to iterate over children prop sometimes, and having used two of the children utility methods React.Children.map and React.Children.toArray, let’s refresh our memory about one of them: React.Children.toArray.

 

React.Children.toArray #

Let’s start by seeing with an example what this method does and where it might be useful.

import { Children } from 'react'

function Debugger({children}) {
  // let’s log some things
  console.log(children);
  console.log(
    Children.toArray(children)
  )
  return children;
}

const fruits = [
  {name: "apple", id: 1},
  {name: "orange", id: 2},
  {name: "mango", id: 3}
]

export default function App() {
  return (
    <Debugger>
        <a
          href="https://css-tricks.com/"
          style={{padding: '0 10px'}}
        >
          CSS Tricks
        </a>

        <a
          href="https://smashingmagazine.com/"
          style={{padding: '0 10px'}}
        >
          Smashing Magazine
        </a>

        {
          fruits.map(fruit => {
            return (
              <div key={fruit.id} style={{margin: '10px'}}>
                {fruit.name}
              </div>
            )
          })
        }
    </Debugger>
  )
}

Take a look at the Codesandbox demo. We have a Debugger component, which does nothing much in terms of rendering — it just returns children as is. But it does log two values: children and React.Children.toArray(children).

If you open up the console, you’d be able to see the difference.

  • The first statement which logs children prop, shows the following as its value’s data structure:
[
  Object1, ----> first anchor tag
  Object2, ----> second anchor tag
  [
    Object3, ----> first fruit
    Object4, ----> second fruit
    Object5] ----> third fruit
  ]
]
  • The second statement which logs React.Children.toArray(children) logs:
[
  Object1, ----> first anchor tag
  Object2, ----> second anchor tag
  Object3, ----> first fruit
  Object4, ----> second fruit
  Object5, ----> third fruit
]

Let’s read the method’s documentation in React docs to make sense of what is happening.

React.Children.toArray returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice children before passing it down.

Let’s break that down:

  1. Returns the children opaque data structure as a flat array.
  2. With keys assigned to each child.

The first point says that that children (which is an opaque data structure, meaning it can be an object, array, or a function, as described earlier) is converted to a flat array. Just like we saw in the example above. Additionally, this GitHub issue comment also explains its behavior:

It (React.Children.toArray) does not pull children out of elements and flatten them, that wouldn’t really make any sense. It flattens nested arrays and objects, i.e. so that [['a', 'b'],['c', ['d']]] becomes something similar to ['a', 'b', 'c', 'd'].

React.Children.toArray(
  [
    ["a", "b"],
    ["c", ["d"]]
  ]
).length === 4;

Let’s see what the second point (‘With keys assigned to each child.’) says, by expanding one child each from the previous logs of the example.

Expanded Child From console.log(children) #

{
  $$typeof: Symbol(react.element),
  key: null,
  props: {
    href: "https://smashingmagazine.com",
    children: "Smashing Magazine",
    style: {padding: "0 10px"}
  },
  ref: null,
  type: "a",
  // … other properties
}

Expanded Child From console.log(React.Children.toArray(children)) #

{
  $$typeof: Symbol(react.element),
  key: ".0",
  props: {
    href: "https://smashingmagazine.com",
    children: "Smashing Magazine",
    style: {padding: "0 10px"}
  },
  ref: null,
  type: "a",
  // … other properties
}

As you can see, besides flattening the children prop into a flat array, it also adds unique keys to each of its children. From the React docs:

React.Children.toArray() changes keys to preserve the semantics of nested arrays when flattening lists of children. That is, toArray prefixes each key in the returned array so that each element’s key is scoped to the input array containing it.

Because the .toArray method might change the order and place of children, it has to make sure that it maintains unique keys for each of them for reconciliation and rendering optimization.

Let’s give a little bit more attention to so that each element’s key is scoped to the input array containing it., by looking at the keys of each element of the second array (corresponding to console.log(React.Children.toArray(children))).

import { Children } from 'react'

function Debugger({children}) {
  // let’s log some things
  console.log(children);
  console.log(
    Children.map(Children.toArray(children), child => {
      return child.key
    }).join('\n')
  )
  return children;
}

const fruits = [
  {name: "apple", id: 1},
  {name: "orange", id: 2},
  {name: "mango", id: 3}
]

export default function App() {
  return (
    <Debugger>
        <a
          href="https://css-tricks.com/"
          style={{padding: '0 10px'}}
        >
          CSS Tricks
        </a>
        <a
          href="https://smashingmagazine.com/"
          style={{padding: '0 10px'}}
        >
          Smashing Magazine
        </a>
        {
          fruits.map(fruit => {
            return (
              <div key={fruit.id} style={{margin: '10px'}}>
                {fruit.name}
              </div>
            )
          })
        }
    </Debugger>
  )
}
.0  ----> first link
.1  ----> second link
.2:$1 ----> first fruit
.2:$2 ----> second fruit
.2:$3 ----> third fruit

As you can see that the fruits, which were originally a nested array inside the original children array, have keys that are prefixed with .2. The .2 corresponds to the fact that they were a part of an array. The suffix, namely :$1 ,:$2, :$3, is corresponding to the jsx parent div element corresponding to fruits. If we had used index as key instead, then we’d have got :0, :1, :2 as suffixes.

So suppose you had three level of nesting inside children array, like so:

import { Children } from 'react'

function Debugger({children}) {
  const retVal = Children.toArray(children)
  console.log(
    Children.map(retVal, child => {
      return child.key
    }).join('\n')
  )
  return retVal
}

export default function App() {
  const arrayOfReactElements = [
    <div key="1">First</div>,
    [
      <div key="2">Second</div>,
      [
        <div key="3">Third</div>
      ]
    ]
  ];
  return (
    <Debugger>
      {arrayOfReactElements}
    </Debugger>
  )
}

The keys will look like

.$1
.1:$2
.1:1:$3

Check the Codesandbox demo. The $1, $2, $3 suffixes are because of the original keys put on the React elements in an array, otherwise React complains of lack of keys 😉 .

From whatever we’ve read so far we can come to two use cases for React.Children.toArray.

  1. If there’s an absolute need that children should always be an array, you can use React.Children.toArray(children) instead. It’ll work perfectly even when children is an object or a function too.

  2. If you have to sort, filter, or slice children prop you can rely on React.Children.toArray to always preserve unique keys of all the children.

There’s a problem with React.Children.toArray 🤔. Let’s look at this piece of code to understand what the problem is:

import { Children } from 'react'

function List({children}) {
  return (
    <ul>
      {
        Children.toArray(
          children
        ).map((child, index) => {
          return (
            <li
              key={child.key}
            >
              {child}
            </li>
          )
        })
      }
    </ul>
  )
}

export default function App() {
  return (
    <List>
      <a
        href="https://css-tricks.com"
        style={{padding: '0 10px'}}
      >
        Google
      </a>
      <>
        <a
          href="https://smashingmagazine.com"
          style={{padding: '0 10px'}}
        >
          Smashing Magazine
        </a>
        <a
          href="https://arihantverma.com"
          style={{padding: '0 10px'}}
        >
          {"Arihant’s Website"}
        </a>
      </>
    </List>
  )
}

Check the Codesandbox demo. If you see what gets rendered for the children of the fragment, you’ll see that both of the links get rendered inside one li tag! 😱

This is because React.Children.toArray doesn’t traverse into fragments. So what can we do about it? Fortunately, nothing 😅 . We already have an open-sourced package called react-keyed-flatten-children. It’s a small function that does its magic.

Let’s see what it does. In pseudo-code (these points are linked in the actual code below), it does this:

  1. It is a function that takes children as its only necessary argument.
  2. Iterates over React.Children.toArray(children) and gathers children in an accumulator array.
  3. While iterating, if a child node is a string or a number, it pushes the value as is in the accumulator array.
  4. If the child node is a valid React element, it clones it, gives it the appropriate key, and pushes it to the accumulator array.
  5. If the child node is a fragment, then the function calls itself with fragment’s children as its argument (this is how it traverses through a fragment) and pushes the result of calling itself in the accumulator array.
  6. While doing all this it keeps the track of the depth of traversal (of fragments), so that the children inside fragments would have correct keys, the same way as keys work with nested arrays, as we saw earlier above.
import {
  Children,
  isValidElement,
  cloneElement
} from "react";

import { isFragment } from "react-is";

import type {
  ReactNode,
  ReactChild,
} from 'react'

/*************** 1. ***************/
export default function flattenChildren(
  // only needed argument
  children: ReactNode,
  // only used for debugging
  depth: number = 0,
  // is not required, start with default = []
  keys: (string | number)[] = [] 
): ReactChild[] {
  /*************** 2. ***************/
  return Children.toArray(children).reduce(
    (acc: ReactChild[], node, nodeIndex) => {
      if (isFragment(node)) {
        /*************** 5. ***************/
        acc.push.apply(
          acc,
          flattenChildren(
            node.props.children,
            depth + 1,
            /*************** 6. ***************/
            keys.concat(node.key || nodeIndex)
          )
        );
      } else {
        /*************** 4. ***************/
        if (isValidElement(node)) {
          acc.push(
            cloneElement(node, {
              /*************** 6. ***************/
              key: keys.concat(String(node.key)).join('.')
            })
          );
        } else if (
          /*************** 3. ***************/
          typeof node === "string"
          || typeof node === "number"
        ) {
          acc.push(node);
        }
      }
      return acc; 
    },
    /*************** Acculumator Array ***************/
    []
  );
}

Let’s retry our previous example to use this function and see for ourselves that it fixes our problem.

import flattenChildren from 'react-keyed-flatten-children'
import { Fragment } from 'react'

function List({children}) {
  return (
    <ul>
      {
        flattenChildren(
          children
        ).map((child, index) => {
          return <li key={child.key}>{child}</li>
        })
      }
    </ul>
  )
}
export default function App() {
  return (
    <List>
      <a
        href="https://css-tricks.com"
        style={{padding: '0 10px'}}
      >
        Google
      </a>
      <Fragment>
        <a
          href="https://smashingmagazine.com"
          style={{padding: '0 10px'}}>
          Smashing Magazine
        </a>
        
        <a
          href="https://arihantverma.com"
          style={{padding: '0 10px'}}
        >
          {"Arihant’s Website"}
        </a>
      </Fragment>
    </List>
  )
}

And here’s the final result (on Codesandbox)! Woooheeee! It works.

As an add-on, if you are new to testing — like I am at the point of this writing — you might be interested in 7 tests written for this utility function. It’ll be fun to read the tests to deduce the functionality of the function.

The Long Term Problem With Children Utilities #

React.Children is a leaky abstraction, and is in maintenance mode.”

Dan Abramov

The problem with using Children methods to change children behavior is that they only work for one level of nesting of components. If we wrap one of our children in another component, we lose composability. Let’s see what I mean by that, by picking up the first example that we saw — the breadcrumbs.

import { Children, cloneElement } from "react";

function Breadcrumbs({ children }) {
  return (
    <ul
      style={{
        listStyle: "none",
        display: "flex",
      }}
    >
      {Children.map(children, (child, index) => {
        const isLast = index === children.length - 1;
        // if (! isLast && ! child.props.link ) {
        //   throw new Error(`
        //     BreadcrumbItem child no.
        //     ${index + 1} should be passed a 'link' prop`
        //   )
        // } 
        return (
          <>
            {child.props.link ? (
              <a
                href={child.props.link}
                style={{
                  display: "inline-block",
                  textDecoration: "none",
                }}
              >
                <div style={{ marginRight: "5px" }}>
                  {cloneElement(child, {
                    isLast,
                  })}
                </div>
              </a>
            ) : (
              <div style={{ marginRight: "5px" }}>
                {cloneElement(child, {
                  isLast,
                })}
              </div>
            )}
            {!isLast && (
              <div style={{ marginRight: "5px" }}>></div>
            )}
          </>
        );
      })}
    </ul>
  );
}

function BreadcrumbItem({ isLast, children }) {
  return (
    <li
      style={{
        color: isLast ? "black" : "blue",
      }}
    >
      {children}
    </li>
  );

}
const BreadcrumbItemCreator = () =>
  <BreadcrumbItem
    link="https://smashingmagazine.com"
  >
    Smashing Magazine
  </BreadcrumbItem>

export default function App() {
  return (
    <Breadcrumbs>
      <BreadcrumbItem
        link="https://goibibo.com/"
      >
        Goibibo
      </BreadcrumbItem>

      <BreadcrumbItem
        link="https://goibibo.com/hotels/"
      >
        Goibibo Hotels
      </BreadcrumbItem>

      <BreadcrumbItemCreator />

      <BreadcrumbItem>
        A Fancy Hotel Name
      </BreadcrumbItem>
    </Breadcrumbs>
  );
}

Take a look at the Codesandbox demo. Although our new component <BreadcrumbItemCreator /> rendered, our Breadcrumb component doesn’t have any way to extract out the link prop from it, because of which, it doesn’t render as link.

To fix this problem React team had come with — now defunct — experimental API called react-call-return.

Ryan Florence’s Video explains this problem in detail, and how react-call-return fixed it. Since the package was never published in any version of React, there are plans to take inspiration from it and make something production-ready.

Conclusion #

To conclude, we learned about:

  1. The React.Children utility methods. We saw two of them: React.Children.map to see how to use it to make compound components, and React.Children.toArray in depth.
  2. We saw how React.Children.toArray converts opaque children prop — which could be either object, array or function — into a flat array, so that one could operate over it in required manner — sort, filter, splice, etc…
  3. We learned that React.Children.toArray doesn’t traverse through React Fragments.
  4. We learned about an open-source package called react-keyed-flatten-children and understood how it solves the problem.
  5. We saw that Children utilities are in maintenance mode because they do not compose well.

You might also be interested in reading how to use other Children methods to do everything you can do with children in Max Stoiber’s blog post React Children Deep Dive.

Resources #

 

Friday, August 7, 2020

Higher-Order Components In React

In this tutorial, we are going to learn about higher-order components, the syntax of higher-order components, as well as use cases for them. In the process, we will build a higher-order component from an existing React component. By the end of this tutorial, you will understand the basics of higher-order components and how to build them.
Higher-order components (HOCs) in React were inspired by higher-order functions in JavaScript. A HOC is an advanced technique for reusing logic in React components. It is a pattern created out of React’s compositional nature.
HOCs basically incorporate the don’t-repeat-yourself (DRY) principle of programming, which you’ve most likely come across at some point in your career as a software developer. It is one of the best-known principles of software development, and observing it is very important when building an application or writing code in general.
In this tutorial, we will learn what a HOC is, its basic structure, some use cases, and finally an example.
Note: Basic knowledge of React and JavaScript will come in handy as you work through this tutorial.

Higher-Order Functions In JavaScript

Before jumping into HOCs in React, let’s briefly discuss higher-order functions in JavaScript. Understanding them is critical to understanding our topic of focus.
Higher-order functions in JavaScript take some functions as arguments and return another function. They enable us to abstract over actions, not just values, They come in several forms, and they help us to write less code when operating on functions and even arrays.
The most interesting part of using higher-order functions is composition. We can write small functions that handle one piece of logic. Then, we can compose complex functions by using the different small functions we have created. This reduces bugs in our code base and makes our code much easier to read and understand.
JavaScript has some of these functions already built in. Some examples of higher-order functions are the following:
  • .forEach()
    This iterates over every element in an array with the same code, but does not change or mutate the array, and it returns undefined.
  • .map()
    This method transforms an array by applying a function to all of its elements, and then building a new array from the returned values.
  • .reduce()
    This method executes a provided function for each value of the array (from left to right).
  • .filter()
    This checks every single element in an array to see whether it meets certain criteria as specified in the filter method, and then it returns a new array with the elements that match the criteria.
So many higher-order functions are built into JavaScript, and you can make your own custom ones.

An Example Of Custom Higher-Order Function

Suppose we are asked to write a function that formats integers as currencies, including some customization of specifying the currency symbol and adding a decimal separator for the currency amount. We can write a higher-other function that takes the currency symbol and also the decimal separator. This same function would then format the value passed to it with the currency symbol and decimal operators. We would name our higher-order function formatCurrency.
const formatCurrency = function( 
    currencySymbol,
    decimalSeparator  ) {
    return function( value ) {
        const wholePart = Math.trunc( value / 100 );
        let fractionalPart = value % 100;
        if ( fractionalPart < 10 ) {
            fractionalPart = '0' + fractionalPart;
        }
        return `${currencySymbol}${wholePart}${decimalSeparator}${fractionalPart}`;
    }
}
formatCurrency returns a function with a fixed currency symbol and decimal separator.
We then pass the formatter a value, and format this value with the function by extracting its whole part and the fractional part. The returned value of this function is constructed by a template literal, concatenating the currency symbol, the whole part, the decimal separator, and the fractional part.
Let’s use this higher-order function by assigning a value to it and seeing the result.
> getLabel = formatCurrency( '$', '.' );
 
> getLabel( 1999 )
"$19.99" //formatted value
 
> getLabel( 2499 )
"$24.99" //formatted value
You might have noticed that we created a variable named getLabel, then assigned our formatCurrency higher-order function, and then passed the currency formatters to the function, which is the currency symbol and a decimal separator. To make use of the function, we call getLabel, which is now a function, and we pass in the value that needs to be formatted. That’s all! We have created a custom higher order of our choice.

What Is A Higher-Order Component?

A higher-order component (HOC) is an advanced element for reusing logic in React components. Components take one or more components as arguments, and return a new upgraded component. Sounds familiar, right? They are similar to higher-order functions, which take some functions as an argument and produce a new function.
HOCs are commonly used to design components with certain shared behavior in a way that makes them connected differently than normal state-to-props pattern.

Facts About HOCs

  1. We don’t modify or mutate components. We create new ones.
  2. A HOC is used to compose components for code reuse.
  3. A HOC is a pure function. It has no side effects, returning only a new component.
Here are some examples of real-world HOCs you might have come across:
react-reduxconnect(mapStateToProps, mapDispatchToProps)(UserPage)
react-routerwithRouter(UserPage)
material-uiwithStyles(styles)(UserPage)

Structure Of A Higher-Order Component

A HOC is structured like a higher-order function:
  • It is a component.
  • It takes another component as an argument.
  • Then, it returns a new component.
  • The component it returns can render the original component that was passed to it.
The snippet below shows how a HOC is structured in React:

import React from 'react';
// Take in a component as argument WrappedComponent
const higherOrderComponent = (WrappedComponent) => {
// And return another component
  class HOC extends React.Component {
    render() {
      return <WrappedComponent />;
    }
  }
  return HOC;
};
We can see that higherOrderComponent takes a component (WrappedComponent) and returns another component inside of it. With this technique, whenever we need to reuse a particular component’s logic for something, we can create a HOC out of that component and use it wherever we like.

Use Cases

In my experience as a front-end engineer who has been writing React for a while now, here are some use cases for HOCs.
Show a loader while a component waits for data
Most of the time, when building a web application, we would need to use a loader of some sort that is displayed while a component is waiting for data to be passed to its props. We could easily use an in-component solution to render the loader, which would work, but it wouldn’t be the most elegant solution. Better would be to write a common HOC that can track those props; and while those props haven’t been injected or are in an empty state, it can show a loading state.
To explain this properly, let’s build a list of categories of public APIs, using its open API. We tend to handle list-loading, so that our clients don’t panic when the API we are getting data from takes so much time to respond.
Let’s generate a React app:
npx create-react-app repos-list
A basic list component can be written as follows:
//List.js
import React from 'react';
const List = (props) => {
  const { repos } = props;
  if (!repos) return null;
  if (!repos.length) return <p>No repos, sorry</p>;
  return (
    <ul>
      {repos.map((repo) => {
        return <li key={repo.id}>{repo.full_name}</li>;
      })}
    </ul>
  );
};
export default List;
The code above is a list component. Let’s break down the code into tiny bits so that we can understand what is happening.
const List = (props) => {};
Above, we initialize our functional component, named List, and pass props to it.
const { repos } = props;
Then, we create a constant, named repos, and pass it to our component props, so that it can be used to modify our component.
if (!repos) return null;
if (!repos.length) return <p>No repos, sorry</p>;
Above, we are basically saying that, if after fetching has completed and the repos prop is still empty, then it should return null. We are also carrying out a conditional render here: If the length of the repos prop is still empty, then it should render “No repos, sorry” in our browser.
return (
    <ul>
      {repos.map((repo) => {
        return <li key={repo.id}>{repo.full_name}</li>;
      })}
    </ul>
  );
Here, we are basically mapping through the repos array and returning a list of repos according to their full names, with a unique key for each entry.
Now, let’s write a HOC that handles loading, to make our users happy.
//withdLoading.js
import React from 'react';
function WithLoading(Component) {
  return function WihLoadingComponent({ isLoading, ...props }) {
    if (!isLoading) return <Component {...props} />;
    return <p>Hold on, fetching data might take some time.</p>;
  };
}
export default WithLoading;
This would display the text “Hold on, fetching data might take some time” when the app is still fetching data and the props are being injected into state. We make use of isLoading to determine whether the component should be rendered.
Now, in your App.js file, you could pass the loading logic to WithLoading, without worrying about it in your List .
import React from 'react';
import List from './components/List.js';
import WithLoading from './components/withLoading.js';
const ListWithLoading = WithLoading(List);
class App extends React.Component {
  state = {
{
  };
  componentDidMount() {
    this.setState({ loading: true });
    fetch(`https://api.github.com/users/hacktivist123/repos`)
      .then((json) => json.json())
      .then((repos) => {
        this.setState({ loading: false, repos: repos });
      });
  }
  render() {
    return (
      <ListWithLoading
        isLoading={this.state.loading}
        repos={this.state.repos}
      />
    );
  }
}
export default App;
The code above is our entire app. Let’s break it down to see what is happening.
class App extends React.Component {
  state = {
    loading: false,
    repos: null,
  };
  componentDidMount() {
    this.setState({ loading: true });
    fetch(`https://api.github.com/users/hacktivist123/repos`)
      .then((json) => json.json())
      .then((repos) => {
        this.setState({ loading: false, repos: repos });
      });
  }
All we are doing here is creating a class component named App(), then initializing state with two properties, loading: false, and repos: null,. The initial state of loading is false, while the initial state of repos is also null.
Then, when our component is mounting, we set the state of the loading property to true, and immediately make a fetch request to the API URL that holds the data we need to populate our List component. Once the request is complete, we set the loading state to false and populate the repos state with the data we have pulled from the API request.
const ListWithLoading = WithLoading(List);
Here, we create a new component named ListWithLoading and pass the WithLoading HOC that we created and also the List component in it.
render() {
    return (
      <ListWithLoading
        isLoading={this.state.loading}
        repos={this.state.repos}
      />
    );
  }
Above, we render the ListWithLoading component, which has been supercharged by the WithLoading HOC that we created and also the List component in it. Also, we pass the loading state’s value and the repos state’s value as props to the component.

Conditionally Render Components

Suppose we have a component that needs to be rendered only when a user is authenticated — it is a protected component. We can create a HOC named WithAuth() to wrap that protected component, and then do a check in the HOC that will render only that particular component if the user has been authenticated.
A basic withAuth() HOC, according to the example above, can be written as follows:
// withAuth.js
import React from "react";
export function withAuth(Component) {
    return class AuthenticatedComponent extends React.Component {
        isAuthenticated() {
            return this.props.isAuthenticated;
        }

        /**
         * Render
         */
        render() {
            const loginErrorMessage = (
                <div>
                    Please <a href="/login">login</a> in order to view this part of the application.
                </div>
            );

            return (
                <div>
                    { this.isAuthenticated === true ? <Component {...this.props} /> : loginErrorMessage }
                </div>
            );
        }
    };
}

export default withAuth;
The code above is a HOC named withAuth. It basically takes a component and returns a new component, named AuthenticatedComponent, that checks whether the user is authenticated. If the user is not authenticated, it returns the loginErrorMessage component; if the user is authenticated, it returns the wrapped component.
Note: this.props.isAuthenticated has to be set from your application’s logic. (Or else use react-redux to retrieve it from the global state.)
To make use of our HOC in a protected component, we’d use it like so:
// MyProtectedComponent.js
import React from "react";
import {withAuth} from "./withAuth.js";

export class MyProectedComponent extends React.Component {
    /**
     * Render
     */
    render() {
        return (
            <div>
                This is only viewable  by authenticated users.
            </div>
        );
    }
}

// Now wrap MyPrivateComponent with the requireAuthentication function 
export default withAuth(MyPrivateComponent);
Here, we create a component that is viewable only by users who are authenticated. We wrap that component in our withAuth HOC to protect the component from users who are not authenticated.

Provide Components With Specific Styling

Continuing the use case above, based on whatever UI state you get from the HOC, you can render specific styles for specific UI states. For example, if the need arises in multiple places for styles like backgroundColor, fontSize and so on, they can be provided via a HOC by wrapping the component with one that just injects props with the specific className.
Take a very simple component that renders “hello” and the name of a person. It takes a name prop and some other prop that can affect the rendered JavaScript XML (JSX).
// A simple component 
const HelloComponent = ({ name, ...otherProps }) => (
 <div {...otherProps}>Hello {name}!/div>
);
Let’s create a HOC named withStyling that adds some styling to the “hello” text.
const withStyling = (BaseComponent) => (props) => (
  <BaseComponent {...props} style={{ fontWeight: 700, color: 'green' }} />
);
In order to make use of the HOC on our HelloComponent, we wrap the HOC around the component. We create a pure component, named EnhancedHello, and assign the HOC and our HelloComponent, like so :
const EnhancedHello = withStyling(HelloComponent);
To make a change to our HelloComponent, we render the EnhancedHello component:
<EnhancedHello name='World' />
Now, the text in our HelloComponent becomes this:
<div style={{fontWeight: 700, color: 'green' }}>Hello World</div>

Provide A Component With Any Prop You Want

This is a popular use case for HOCs. We can study our code base and note what reusable prop is needed across components. Then, we can have a wrapper HOC to provide those components with the reusable prop.
Let’s use the example above:
// A simple component 
const HelloComponent = ({ name, ...otherProps }) => (
 <div {...otherProps}>Hello {name}!</div>
);
Let’s create a HOC named withNameChange that sets a name prop on a base component to “New Name”.
const withNameChange = (BaseComponent) => (props) => (
  <BaseComponent {...props} name='New Name' />
);
In order to use the HOC on our HelloComponent, we wrap the HOC around the component, create a pure component named EnhancedHello2, and assign the HOC and our HelloComponent like so:
const EnhancedHello2 = withNameChange(HelloComponent);
To make a change to our HelloComponent, we can render the EnhancedHello component like so:
<EnhancedHello />
Now, the text in our HelloComponent becomes this:
<div>Hello New World</div>
To change the name prop, all we have to do is this:
<EnhancedHello name='Shedrack' />
The text in our HelloComponent becomes this:
<div>Hello Shedrack</div>

Let’s Build A Higher-Order Component

In this section, we will build a HOC that takes a component that has a name prop, and then we will make use of the name prop in our HOC.
So, generate a new React app with create-react-app, like so:
npx create-react-app my-app
After it is generated, replace the code in your index.js file with the following snippet.
import React from 'react';
import { render } from 'react-dom';
const Hello = ({ name }) =>
  <h1>
    Hello {name}!
  </h1>;

function withName(WrappedComponent) {
  return class extends React.Component {
    render() {
      return <WrappedComponent name="Smashing Magazine" {...this.props} />;
    }
  };
}
const NewComponent = withName(Hello);
const App = () =>
  <div>
    <NewComponent />
  </div>;
render(<App />, document.getElementById('root')); 
 
 
Let’s go through the snippet bit by bit.
const Hello = ({ name }) =>
  <h1>
    Hello {name}!
  </h1>;
Here, we create a functional component that has a prop called name. In this functional component, we render the “Hello” and the value of the name prop in an h1 tag.
function withName(WrappedComponent) {
  return class extends React.Component {
    render() {
      return <WrappedComponent name="Smashing Magazine" {...this.props} />;
    }
  };
}
Above, we create a higher-order functional component named withName(). Then, we return an anonymous class component inside that renders the component wrapped in the HOC. And we assign a value to the prop of the wrapped component.
const NewComponent = withName(Hello);
Here, we create a new component named NewComponent. We use the HOC that we created, and assign to it the functional component that we created at the start of the code base, named hello.
const App = () =>
  <div>
    <NewComponent />
  </div>;
render(<App />, document.getElementById('root'));
All we are doing above is creating another functional component, named App. It renders the NewComponent that we upgraded with our HOC in a div. Then, we use the react-dom function render to display the component in the browser.
That’s all we need to do! Our withName function takes a component as an argument and returns a HOC. A few months from now, if we decide to change things around, we only have to edit our HOC.

Conclusion

I hope you’ve enjoyed working through this tutorial. You can read more about higher-order components in the references listed below. If you have any questions, leave them in the comments section below. I’ll be happy to answer every one.

Resources And References