Recompose

As soon as we become familiar with HoCs, we realize how powerful they are and how we can get the most out of them.

There is a popular library called recompose which provides many useful HoCs and also a way to compose them nicely.

The HoCs that the library offers are small utilities that we can use to wrap our components, moving away from some of their logic and making them dumber and more reusable.

Consider that your component is receiving a user object from an API and that this user object has many attributes.

Letting components receive arbitrary objects is not a good practice because it relies on the fact that the component knows the shape of the object and, most importantly, if the object changes, the component breaks.

A better way for a component to receive props from the parent is to define each single property using primitives.

We have a Profile component to display username and age, as follows:

  const Profile = ({ user: { username, age } }) => ( 
<div>
<div>Username: {username}</div>
<div>Age: {age}</div>
</div>
);

Profile.propTypes = {
user: object
};

If you want to change its interface to receive single props instead of the full user object, we can do so with the flattenProp HoC provided by recompose.

Let's see how it works.

We first change the component to declare single properties, as follows:

  const Profile = ({ username, age }) => ( 
<div>
<div>Username: {username}</div>
<div>Age: {age}</div>
</div>
);

Profile.propTypes = {
username: string,
age: number
};

Then, we enhance it with the HoC:

  const ProfileWithFlattenUser = flattenProp('user')(Profile);

You may have noted here that we are using the HoC in a slightly different way. Some of them, in fact, use the partial application to receive the parameters first, which is a functional approach.

Their signature is something similar to the following:

  const HoC = args => Component => EnhancedComponent;

What we can do is create a function using the first call and wrap our component into it:

  const withFlattenUser = flattenProp('user');
const ProfileWithFlattenUser = withFlattenUser(Profile);

Great! Now, suppose for some reason that we want to change the attribute username to make this component more generic and reusable.

We can use renameProp, which the recompose library gives us, and update our component like this:

  const Profile = ({ name, age }) => ( 
<div>
<div>Name: {name}</div>
<div>Age: {age}</div>
</div>
);

Profile.propTypes = {
name: string,
age: number
};

Now, we want to apply multiple HoC components: one for flattening the user prop and one to rename a single prop from the user object, but concatenating functions does not seem like a good idea.

Here is where the compose function of recompose comes in handy.

We can pass multiple HoCs to it and get a single enhanced HoC:

  const enhance = compose( 
flattenProp('user'),
renameProp('username', 'name')
);

Then, we can apply it to our component in the following way:

  const EnhancedProfile = enhance(Profile);

This is more convenient and elegant.

With recompose, we are not limited to using only the HoCs provided by the library—we can compose our HoC in the same way or even use them all together:

  const enhance = compose( 
flattenProp('user'),
renameProp('username', 'name'),
withInnerWidth
);

As you can see here, the compose function is very powerful, and it makes the code more readable.

We can concatenate multiple HoCs to keep our components as simple as possible.

It is important not to abuse HoCs because with every abstraction comes problems; in this case, the trade-off is related to performance.

You have to think that every time you wrap a component into a higher order one, you are adding a new render function, a new life cycle method call, and memory allocation.

For that reason, it is important to think carefully about when it makes sense to use an HoC and when it is better to rethink your structure.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.71.237