Refactoring a render prop with hooks

Sean McPherson
3 min readOct 25, 2018

--

Just a few weeks ago, I published a guide on creating render props components. Today, at React Conf 2018, the React team announced “Hooks”, a new feature proposal in React v16.7.0-alpha, that will change the way we think about components.

Hooks serve as a method for abstracting state-based logic and lifecycle methods into reusable functions. These hooks replace a number of the most common use cases for render props.

So let’s look at how to convert a simple render prop component into a hook!

The old: render prop

In my previous article, we created a render prop component called “Open” that kept track of an open/close state and shared a method to change it. Here’s the code:

import React from 'react'export default class Open extends React.Component {
state = { isOpen: false }
toggle = () => this.setState({ isOpen: !this.state.isOpen })render() {
const renderProps = {
isOpen: this.state.isOpen,
toggle: this.toggle
}
return typeof this.props.children === 'function'
? this.props.children(renderProps)
: this.props.children
}
}

Open could then be implemented in typical render prop fashion:

export const App = () => (
<Open>
{openProps => (
<div className="app">
{openProps.isOpen
&& <NewMenu toggle={openProps.toggle} />}
<main>
<button
onClick={openProps.toggle}
type="button"
>
MENU
</button>
<Welcome />
</main>
</div>
)}
</Open>
)

Not bad, but let’s refactor this with hooks.

The new: hook

React’s Hook API allows us to implement state on purely functional components. Let’s create it one step at a time:

1. useState

Before we get to that, we’re going to name our function useOpen. Prefacing hooks with use is a convention the React team prefers. Now, we’ll import useState function from React:

import { useState } from 'react'function useOpen() {
const [isOpen, setIsOpen] = useState(false)
// isOpen is initialized to the passed value: false
// setIsOpen is a function that can update the value
return { isOpen, setIsOpen }
}

We call useState and pass it an initial value. This function returns an array with the value and a function for updating that value. To access these data, we’ll create variables by destructuring the array returned by useState.

At this point, isOpen is assigned to false and setIsOpen is a function that is waiting to update that value. Finally, we return those variables in an object.

2. Create “method”

Our render prop had one method to toggle isOpen between true and false. We can implement the same functionality, but with a basic function:

import { useState } from 'react'function useOpen() {
const [isOpen, setIsOpen] = useState(false)
function toggle {
setIsOpen(!isOpen)
}
return { isOpen, toggle }
}

The toggle function calls the set function provided by useState and provides the opposite value of isOpen. Then, we return toggle instead of setIsOpen.

Now we can set it all up!

3. Implement useOpen

First, we have to remove all the references to the Open and all associated nesting in our App component. Then, we’ll:

  1. Import useOpen
  2. Create our variables by calling useOpen
  3. Remove all references to openProps

Here’s what we’re left with:

import useOpen from './hooks/useOpen'export const App = () => {
const { isOpen, toggle } = useOpen()
return (
<div className="app">
{isOpen
&& <NewMenu toggle={toggle} />}
<main>
<button
onClick={toggle}
type="button"
>
MENU
</button>
<Welcome />
</main>
</div>
)
}

No more parent components, passed functions, or faux-nesting. Just grabbing variables from a function and referencing them in the return of your component.

That’s it! We’ve recreated a basic render prop component as a hook.

Summary

Hooks are a “new feature proposal” and therefore are not ready for implementation in an app. That being said, the React team sees hooks and class-less components as the future of the library. Read here for the motivation behind this feature and the future direction of React.

While the syntax of hooks are less intuitive than render props, the implementation is more straightforward.

For a more detailed explanation of hooks, checkout the official docs (and Dan Abramov’s and Ryan Florence’s talks at React Conf 2018).

Hopefully that helped! Let me know what you think about React’s new hooks in the comments below.

Happy coding!

--

--

Sean McPherson

Software engineer @ Khan Academy. JavaScript, React, and Node.js. Formerly Niche & TSYS. Soli Deo gloria.