How to Use Recompose to Transform React Development

Lately, I've spent time playing with the recompose library for React. 

Briefly stated, recompose is a set of utility functions. These functions help to encapsulate specific functionality you want to reuse. In practice, with recompose you might find yourself creating higher order components or individual functional components.

In this article, I'm going to focus on creating functional components with recompose.

Why you need to create functional components

Creating a component in React is simple. Typically, you might create a class-based component, inheriting from React's own Component class. Here is a contrived example:

https://gist.github.com/tortillaj/8b24159547cea434c398ddcd05e46ad0#file-class-component-js

This is a simplistic example of a component that creates a button. The button is provided an onClick method, a type, and a className. These props are applied to the eventual <button> element created in HTML.

The onClick method might be long running, so we give the button some internal state to track the loading time. While the onClick is loading, the button contents show a Loading component inside of the button text. I don't have the Loading component here in the example, so let's pretend it's an hour glass or a loading animation.

I should state here that there's nothing exactly wrong with creating a class-based component. However, creating a functional component is easier to handle and more elegant. A functional component only knows what you tell it; there is no inherited functionality from some other class. It's easier to test because you give it variables, just like a regular function.

Also, it's easier to reuse components that you know care about their presentation only. The only functionality or side effects are those you tell it about when you use them. Specifically, when using the functional component, the container where it's used will define any props you pass into the component.

Let's see what our button component looks like as a functional component.

https://gist.github.com/tortillaj/07e8e955981abda38217a97b4445f378

Ok! This is far simpler to understand, right? 

The Button component is a simple function. It receives the props as variables passed to it, and renders the <button> element using those props.

As it stands, our functional component needs to be provided the isLoading prop from the container or component where it's used. The functional component doesn't have its own state to track because it's "dumb."

Also, our class component had the doSomething method, which wrapped around the onClick method passed to it. We lost this in our functional component. This loss may not be a big deal, depending on the use case of the component.

Finally, we also lost our prop validation. The class-based component defined the prop types, but the functional component does not have this definition.

Enhancing your component with recompose

We can get some of the functionality we had from the class-based component back by adding recompose to the mix! I'll show you the example first.

https://gist.github.com/tortillaj/2a8f59d978e344017c714d280cd97895

Here, I've imported compose, setPropTypes, and defaultProps from recompose. The compose function returns back a composed function, which wraps around the component when it's exported at the bottom of the example.

I called this composed function enhance. You can pick something more inventive, like spiceItUp. Inside enhance, I defined our prop types and default props. 

The example shows a simple enhancement which returns the ability to validate props that are passed to Button. Sweet!

Moving ahead with another recompose enhancement

Now let's take things further! 

It's important to remember here that recompose is actually recomposing your props that are passed to components. I'll illustrate this now.

https://gist.github.com/tortillaj/7a3cddeed09189cde9841b6fd05df1b4

I've now included withHandlers, which is another method provided by recompose. 

First, I overwrote onClick. I did this by adding the onClick method inside withHandlers. First, I executed some other function doSomethingDifferentHere. Then, if there was an onClick method passed to Button, I execute that too. Recompose gives button this new onClick handler instead of the original one. Weird? Cool!

Next, I made up an entirely new method, onHover. This method is invented by recompose within withHandlers. It gets passed into the Button component just like any other prop. When someone hovers the button, lookMomImHovering is executed. 

This is awesome! 

Reusing Button styles for more than just buttons

It's very common in web design where something that is not a button should look exactly like a button. We simply want to share styles and functionality.

For example, a list of content teasers might show a "Read more" or "Learn more" button. In reality, that button is just a link, i.e. and <a> element. According to the design, it needs to look like an actual button.

Can recompose save the day, or do we need to rethink our careers?

https://gist.github.com/tortillaj/3dd894a9b091a96f9d992fc991fd555b

With recompose, it's easy to create higher order components on the fly. Above you'll see that I added the componentFromProp method from recompose. It allows us to create a component auto-magically from a prop!

I told recompose that the prop named "component" should be the prop used in order to create this magical, higher order component. You can see where I did that when I called componentFromProp('component').

With some slight refactoring, I can now use this same component to display any HTML element so that it visually appears like a button. It will have all the same functionality too. 

<Button component="a">This is a link element</a>
<Button component="button">This is a button element</a>
<Button component="p">This is a paragraph element</a>

The three examples above will all appear just like a button. There is no need to have additional styles for different types of elements.

Additionally, you can pass other React components into our new, abstract Button component. For example, react-router gives us the Link component. If I wanted a router link to look just like every other button, I can do that too!

import { Link } from 'react-router'

<Button component={Link}>This is a router link!</Button>

Overall, you can see that recompose provides immense flexibility with how you create and reuse component parts. It's one of my favorite React projects to work with, and hopefully you'll enjoy it too!