How to add state to functional components using recompose

Are you mainly using functional components in your React app but don’t know what is the best way to give them access to lifecycle methods and state?

Could creating a class be a way to handle it? But what about consistency? Is a code base with a mixture of classes and functional component something to strive for?

Do you have a gut feeling others are handling this more elegantly?

Recompose is a library with utility functions for functional React components. We are going to take a closer look at how we can use recompose to add state to our functional components.

Is recompose legit?

Recompose is written by one of the co-authors of Redux, acdlite. It has over 4k stars on Github (I guess that adds some legitimacy). And the library encourages composition which is officially recommended in favor of inheritance.

So it seems legit to me. I use it in production.

The use case

For me, a common development pattern is working “front end first”. That means I start by taking a look at the mockups that the designer (or me sometimes) has sketched up. I then start coding the JSX and CSS and I work mainly with functional components.

Eventually I come to a point where I need state.

So you have a functional component

Let’s look at an example. Imagine you are working on a component that looks like this:

const ExpandButton = () => (
    <div className="expand-button">
        <div className="arrow" >
    </div>
);

It’s a button that has a down arrow in it. The rendered HTML looks like this: (CSS is not included in this post)

A nice looking static button!

Adding state with recompose

Now you realize you need that expand button to actually expand the component when the user clicks on it. So now you need state. Because this is a simple UI thing you decide you don’t need that piece of state in Redux (maybe you read my post about it being fine to have parts of your state in React components).

To add state with recompose, we need to do two things: define the state, and “connect” the state to our component.

1. Define state

One of the utility functions that Recompose provides is withState. The withState function call looks like this:

const enhanceWithExpandedState = withState("expanded", "setExpanded", false);
  • The first argument to withState is the name of the state variable.
  • The second argument is the name of the setter function.
  • And the third argument is the default value of the state variable.
  • A function is returned that we call enhanceWithExpandedState in this case. We will use this function when connecting the state to our component.

2. Connect the state to component

Then you can use that state with your component like this:

const ExpandButton = enhanceWithExpandedState(({ expanded, setExpanded }) => (
    <div className="expand-button" onClick={() => setExpanded(!expanded)}>
        { expanded ? <div className="arrow-down"></div> : <div className="arrow-up"></div>}
    </div>
));

Now our component receives two props, expanded and setExpanded, which we defined previously.

But isn’t state and props different things?

Functional components don’t support the concept of state, it only supports props. Therefore, we need some place to store the state and we use recompose for that. The only way to send data from the state to a functional component is with props. That’s why we receive the state via props.

Comparing with using a class

Just for comparison let’s take a look how it would look to implement this with a class:

class ExpandButtonContainer extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            expanded: false
        };

        this.setExpanded = this.setExpanded.bind(this);
    }
    setExpanded(expanded) {
        this.setState({ expanded });
    }
    render() {
        return (
            <ExpandButton
                expanded={this.state.expanded}
                setExpanded={this.setExpanded} />
        );
    }
}

It’s more code.

So is using a class out of the question?

Does this mean we should only forever do functional components? It depends on the requirements of your application.

These are reasons not to use recompose and stick to classes:

  • Recompose is an extra library which adds to the size of your bundle
  • It’s an extra API to learn for you and all your teammates (and all future teammates)
  • Less code does not always mean more readable code.

These are reasons to use recompose instead of classes:

  • Concise syntax.
  • Easy to move state to other components.
  • Possibility to reuse state definitions.

Next step

You can do much more things with recompose. Life cycle methods, composing higher order components, etc. It’s a nice package and I suggest you check it out more!

Do you want to learn more about recompose and other advanced concepts? Consider signing up for my newsletter to get an email roughly every week with the freshest topics I write about.

Master the React ecosystem!

Get an email everytime I post by signing up to the email list.

Subscribe now and you will get a free code review checklist you can use to improve your own code