React's Render Props Technique in 3 Minutes
Tags: react, javascript, webdev, todayilearned
Published: 2020-05-22 15:53:14

> Grasp this useful technique whilst making some watches ⌚️

# What is it?

A technique for sharing logic between components. Components accept a prop that returns a function responsible for rendering something. This allows our component to focus on other logic.

For those in camp __TL;DR__, scroll down for a demo 👍

# What do render props do?
Handle some or all the rendering logic for a component.

```js
<SomeDataProvider
  render={data => <AwesomeComponent stuff={data.awesome} />}
/>
```
<figcaption>Example component using render props</figcaption>

# When to use?
When you’re repeating patterns/logic across components.

Examples;
- Repeating UI structures
- Hooking into/subscribing to a data source
- Hooking into global events (scroll, resize, etc.)

# A Silly Example
Let’s create a watch ⌚️ Our watch component will use `moment.js`, a date and time utility library.

Every `1000ms` we set the state to a new `Moment`. The state change triggers a render and we display the time.

```js
const Watch = () => {
  const [date, setDate] = useState(moment())
  useEffect(() => {
    const TICK = setInterval(() => setDate(moment()), 1000)
    return () => {
      clearInterval(TICK)
    }
  }, [])
  return (
    <Strap>
      <Bezel>
        <Screen>
          <Face>
            <Value>{date.format('HH')}</Value>
            <Value>{date.format('mm')}</Value>
          </Face>
        </Screen>
      </Bezel>
    </Strap>
  )
}
```
<figcaption>First watch implementation</figcaption>

{% codepen https://codepen.io/jh3y/pen/MWaLxPy %}

Don’t worry about `Strap`, `Bezel`, `Screen`, etc. or any of the styling. We are __only__ concerned with the technique.

But what if we wanted a watch with a different face? Many wearables allow us to change the watch face. Do we create a new `Watch` variation for each face? No 👎

This is where a `render` prop comes into play. We can adjust `Watch` to utilise one for rendering a watch face. `Watch` becomes a component that provides the current time and passes that to a `render` prop.

```js
const Watch = ({face}) => {
  const [date, setDate] = useState(moment())
  useEffect(() => {
    const TICK = setInterval(() => setDate(moment()), 1000)
    return () => {
      clearInterval(TICK)
    }
  }, [])
  return (
    <Strap>
      <Bezel>
        <Screen>
          {face(date)}
        </Screen>
      </Bezel>
    </Strap>
  )
}
```

Now we can create stateless face components that take a `Moment` and render it in different ways.

Extracting our initial implementation might look something like

```
const CustomFace = date => (
  <Face>
    <Value>{date.format('HH')}</Value>
    <Value>{date.format('mm')}</Value>
  </Face>
)
// JSX to render being <Watch face={CustomFace} />
```

{% codepen https://codepen.io/jh3y/pen/oNjmryp %}

What if we don’t pass in `face`? We’d get a blank watch. But we could rename `CustomFace` to `DefaultFace` and make it a `defaultProp` on `Watch` 👍

{% codepen https://codepen.io/jh3y/pen/bGVzPOX %}

Nice 👍

Let’s create a new face. An analog one 🕔

```js
const AnalogFace = date => {
  const seconds = (360 / 60) * date.seconds()
  const minutes = (360 / 60) * date.minutes()
  const hours = (360 / 12) * date.format('h')
  return (
    <Face>
      <Hand type='seconds' value={seconds}/>
      <Hand type='minutes' value={minutes}/>
      <Hand value={hours}/>      
    </Face>
  )
}
```

This one takes the date and displays it with hands ✋

{% codepen https://codepen.io/jh3y/pen/abvXgxL %}

We could then extend this to create a slew of different watch faces 🤓 No need to repeat the logic.

```js
const App = () => (
  <Fragment>
    <Watch face={DayFace} />
    <Watch />
    <Watch face={AnalogFace} />
    <Watch face={DateFace} />
    <Watch face={SecondsFace} />
  </Fragment>
)

render(<App />, ROOT)
```

Giving us

{% codepen https://codepen.io/jh3y/pen/JjYxgjp %}

And that’s it!

Using a `render` prop on our `Watch` component keeps the logic in one place and stops us from repeating ourselves. This makes things easier to maintain and reuse 💪

# DOs 👍
- Use when there’s an opportunity to share component/render logic

# DON’Ts 👎
- Overuse. Another pattern may be more appropriate.
- Avoid implementing `render` props with `PureComponent`s unless your prop is statically defined

# NOTES ⚠️
- A `render` prop can have any name. `children` is a `render` prop.
- Most components using a `render` prop could also be a higher-order component and vice versa!

# That’s it!
A 3-minute intro to `render` props!

For further reading, check out the [React Docs](https://reactjs.org/docs/render-props.html).

All the demos are available in this [CodePen collection](https://codepen.io/collection/DmpkEB).

-----

As always, any questions or suggestions, please feel free to leave a response or tweet me 🐦!

As always, any questions, please feel free to leave a response or [tweet me](https://twitter.com/jh3yy) 🐦! And say "Hey!" anyway 😎