An Intro to React Higher-Order Components or HOCs

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Fullstack React with TypeScript Masterclass course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Fullstack React with TypeScript Masterclass with a single-time purchase.

Thumbnail for the \newline course Fullstack React with TypeScript Masterclass
  • [00:00 - 00:20] higher order components or Hogs. Let's first break down this name to understand what it means. To grasp what order means, let's have a look at the functions first. Let's have we, let's say we have a function increment that receives a number and returns a number. Inside of this function, we increment the argument A by 1.

    [00:21 - 00:36] Function increment is a regular function that takes a number and returns the sum of this number with 1. It is a first-order function. The twice function is a function that takes another function as an argument and returns a function as a result.

    [00:37 - 00:52] This characteristic makes it a function with an order higher than the first. Basically, any given function that either takes a function as an argument or returns a function as a result or does both is a function with order higher than first, hence the name higher order function.

    [00:53 - 01:17] This kind of function is useful for composition. This term comes from functional programming and essentially it is a mechanism that makes it possible to take simple functions and build more complicated ones based on them. Let's continue with our example here. We can create a function that will increment a number twice. A naive way to do that would be define a function increment twice and inside of it call increment two times.

    [01:18 - 01:36] Here we pass the result of the first increment to the second one. This is not very good because we cannot be sure that there won't be a requirement to increase this number in the future. So if we would have to increment three times, then we would have to define another function and pass the increment function results to each other three times.

    [01:37 - 01:46] But we can use the function twice to achieve the same result as we did with the increment twice. Let's see how it works step by step. We'll look at our twice function once again.

    [01:47 - 02:09] When we call twice and pass the increment as an argument, the variable fn starts carrying the value of the increment function. So after the first step, fn is increment. Then we create an anonymous function that takes an array of arguments of type unknown to prevent this function from calling fn right away, since we only want to prepare and remember which function we plan to call two times in the future.

    [02:10 - 02:26] And then we return the function that we got from the argument of the function twice applied to the arguments that we got from the anonymous function. And then we apply the function from the arguments the second time, thus calling the original function twice.

    [02:27 - 02:36] So if we try to write down the breakdown that we did, it will look like this. Inside of our another increment twice, we basically call the increment function two times.

    [02:37 - 02:45] And surely it results with the same values as the previous function. The only difference here is that this function previously took only one argument, and now it takes an array of arguments.

    [02:46 - 02:55] It is a side effect of the fact that we can now use the function twice with any other function to repeat it. So for example, let's say we want to repeat hello several times.

    [02:56 - 03:04] We define a function, say hello, that looks hello world message. Then we define say hello twice by using function twice on function say hello.

    [03:05 - 03:10] And then we call the say hello twice function. As a result, we'll get the log hello world twice.

    [03:11 - 03:14] Define a hook. A basic implementation of a hook would look like this.

    [03:15 - 03:25] Here we have the factory function with logging that takes a component as an argument and returns a new component. We have the wrapper component that wraps the original component.

    [03:26 - 03:31] And we have the wrapped component that is being enhanced with this hook. When to use Hogs.

    [03:32 - 03:39] We can use Hogs when we need to share functionality between many components. Injectors can extend the functionality of a given component by passing new props to it.

    [03:40 - 03:52] Sometimes Hogs are used to access network requests, provide local storage access, subscribe to event streams or connect components to an application store. The latter was used in the Redux library to connect a component to the Redux store.

    [03:53 - 03:58] These Hogs are often calls providers, but they work basically the same way. Pros and cons.

    [03:59 - 04:04] Hogs provide the static composition possibility. We can remember arguments for the future.

    [04:05 - 04:14] And also Hogs are literal implementation of the decorator pattern. The cons are that first of all, Hogs imply extra encapsulation and implicitness .

    [04:15 - 04:21] Sometimes Hogs hide too much logic inside of them. And it is not clear what will happen when we wrap some component into a hook.

    [04:22 - 04:29] Another downside of Hogs is that they're hard to type. You will have to use generic types and also likely typecasting on the fly.

    [04:30 - 04:33] And overall it's just difficult. And finally Hogs may become two verbose.

    [04:34 - 04:39] Cavets. Note that we cannot wrap a component into a hook inside of the render function.

    [04:40 - 04:52] Basically in runtime reacts diffing algorithm uses component identity to determine whether it should update the existing subtree or throw it away and mount a new one. The problem here isn't just about performance.

    [04:53 - 05:04] Remounting a component causes the state of that component and all of its children to be lost. We must always apply Hogs outside of the component definition so that the resulting component is created only once.

    [05:05 - 05:11] Also remember that all the static methods of the hook should be copied over. Oh and there might be prop names collisions.

    [05:12 - 05:22] Where some props provided by a hook might have the same names as props from the other Hogs or wrappers. These name collisions can lead us to accidentally overridden props.