Recompose is great. Ever used libraries like Lodash or Ramda? Recompose is that, but for React.
This
Becomes this
This style’s really grown on me, and I’d like to share a few of my favorite functions from this awesome utility belt.
withHandlers() and withState()
Let’s say we want to display a user’s name as they type. I’m basing this off the example in the official docs.
Traditionally, our JSX might look like
We need state management to handle the user’s name, so we use this.state.value
. Let’s define that state in the constructor and add a handler to update it.
Our state’s initialized to { value: '' }
and we’ve added an updateValue
method. We’ve already hooked it up in our JSX. Let’s try it out.
Cool, it works. As you type, the username’s updated in real-time.
Here’s a possible Recompose version. Our component will now accept a prop called onChange
.
We’ll add state and a handler to update it using withState
.
withState
accepts three parameters, stateName
, stateUpdaterName
, and initialState
.
In this case we created a piece of state called value
, initialized it as an empty string, and made a function to update it called updateValue
.
Now for withHandlers
.
withHandlers
accepts as an object of handlers: higher-order functions that accept props
and return a handler. Even after the handler’s returned, it can access its parent function’s props
via closure.
updateValue
is the updater function provided by withState
, and we’re using it inside of withHandlers
to set event.target.value
as the new state value. All of this happens inside the handler onChange
, which will be passed to our component as a prop!
Remember MyForm
now calls its onChange
prop whenever the user updates the input box.
Our default export now looks like this
After invoking withState
and withHandlers
, you get back higher-order components. A higher-order component must be invoked with another component.
That’s why we’re passing MyForm
to addHandlers
, then passing addHandlers(MyForm)
to addState
. One decorates the next, uniting to form a greater entity.
And our functionality remains unchanged.
compose()
If you’re familiar with functional programming, you likely recognize compose()
. If not, I’ve written a post explaining it here.
compose
combines n
functions, allowing you to more elegantly nest functions. Let’s refactor our enhanced MyForm
with it.
We previously had this
We’ll import compose
And use it like so
One pattern I’ve seen in the Recompose docs is storing your “enhancements” in a variable, then exporting that variable + your component. Here’s an example.
I’ve adopted this pattern as it makes a lot of sense to me.
Your component is a pure function that takes props
and returns JSX.
Your “enhancements” are higher-order components meant to add or improve upon your component’s functionality.
Defining and combining them in this fashion seems to complement that idea.
I’ll share one more of my favorite higher-order components: lifecycle
.
lifecycle
You might guess by the name, lifecycle
gives your pure, functional component access to React’s lifecycle hooks, meant strictly for classes.
lifecycle
actually uses a class under the hood, but you only deal with functions. And that’s the whole point. Since everything is exposed to you as a function, that’s all you have to think about.
Let’s add it to our enhanceComponent
higher-order component. We’ll import it first.
Then put it down below
As you can see, lifecycle
takes an object of functions, like withHandlers
, but these functions must be named after a valid React lifecycle hook.
We get the following alert on the screen
It’s also preferable to use ES6 method definitions to allow access to this.props
. If you want to call a handler from props
, you’d need this
pointing at the right context.
Let’s say in componentDidMount()
we want to set the username to “Lifecycle hook!”
Resulting in this
That won’t work if we use an arrow function
If we console.log(this)
we get the following
It works if you use an ES5-style function, though.
Nowadays I shy away from ES5 functions, so method definitions will do just fine.
Other utility functions
These are my go-to Recompose functions.
As I’ve begun using RxJS Observables again, some other Recompose functions have caught my interest.
They might be the subject of a future post, here’s a link to the Recompose observable utils docs if you’re interested.
Until next time!