Zeals TECH BLOG

チャットボットでネットにおもてなし革命を起こす、チャットコマース『Zeals』を開発する株式会社Zealsの技術やエンジニア文化について発信します。現在本ブログは更新されておりません。新ブログ: https://medium.com/zeals-tech-blog

React Render Props

f:id:zeals-engineer:20181002105736j:plain

Hi everyone, my name is Javen and I'm a front end engineer at ZEALS. Today I'm gonna teach you about Render Props!!

What are Render Props?

The term “render prop” refers to a simple technique for sharing code between React components using a prop whose value is a function.

Render Props is a React pattern that has gained a lot of attention over the past year or so. Many React engineers have gone through debates on whether High Order Components (HoC) or Render Props are better for their applications. When all is said and done, both patterns are great but each have their own pros and cons. However, today I'm going to discuss Render Props!

This is an example of a render prop component:

<MyRenderProp
  render={({ data }) => (
    <h1>Hi I'm a Render Prop Component! Here is my data: {data}</h1>
  )}
/>

As you can see in this component, "MyRenderProp", there is a "render" prop that is getting passed down. In this prop, there is a function that returns an <h1> element which renders out "data". "data" is a parameter that gets passed to that function. This is the basic gist of a Render Prop component.

When to use Render Props

It's really hard to know when to use a specific React pattern. It usually takes some experience and practice with multiple variations of components to know which pattern to use.

As for Render Props, it is suggested that whenever you want to be able to share state and/or behaviors that are encapsulated by the component, then you should want to use a Render Prop component.

Example in code

I will continue from the above (finished) example in order to demonstrate the effectiveness of Render Props. So in the example above, there is a component called "MyRenderProp" which wants to display some data with the <h1> element. But right now we don't know what that data and "MyRenderProp" looks like, so I will show it in the code below! 😅

import React from 'react';

class MyRenderProp extends React.Component {
  state = { data: 50 };

  handleIncrement = () => this.setState({ data: this.state.data + 1 });

  handleDecrement = () => this.setState({ data: this.state.data - 1 });

  render() {
    return (
      <div>
        {this.props.render({ ...this.state })}
        <button onClick={this.handleIncrement}>Increment 👆</button>
        <button onClick={this.handleDecrement}>Decrement 👇</button>
      </div>
    );
  }
}

In this code, we want to be able to share the value of "data". To achieve this, we can use this.props.render as a function to pass the "data" state to whatever gets rendered through the "render" prop!

Let's see this component in action!!! 😏🙃

function App {
  return (
    <div>
      <MyRenderProp
        render={({ data }) => (
          <h1>Hi I'm a Render Prop Component! Here is my data: {data}</h1>
        )}
      />
      <MyRenderProp
        render={({ data }) => (
          <p>The percentage of people using Render Props: {data}%</p>
        )}
      />
    </div>
  );
}

As you can see, "MyRenderProp" is fully reusable to anything that needs an increment/decrement button with some related data attached to it!

🎉And that's it! Our Render Props component is fully implemented! 🎉

f:id:zeals-engineer:20180925151843p:plain

However, there is another way to write this piece of code in a much nicer, cleaner, and readable way! (Well... at least it is to me...😅)

In our "MyRenderProp" component render function:

render() {
  return (
    <div>
      {this.props.children({ ...this.state })}
      <button onClick={this.handleIncrement}>Increment 👆</button>
      <button onClick={this.handleDecrement}>Decrement 👇</button>
    </div>
  );
}
In our "App" component return function:

return (
  <div>
    <MyRenderProp>
      {({ data }) => (
        <h1>Hi I'm a Render Prop Component! Here is my data: {data}</h1>
      )}
    </MyRenderProp>
    <MyRenderProp>
      {({ data }) => <p>The percentage of people using Render Props: {data}%</p>}
    </MyRenderProp>
  </div>
)

Two things changed:

  1. In the "MyRenderProp" component, this.props.render got changed to this.props.children.
  2. The "render" prop function on "MyRenderProp" got moved in between the opening and closing tags of "MyRenderProp".

Anything in between the opening and closing tags of a component can be considered a child of that component. That is why we can remove the "render" prop and replace this.props.render({ ... }) with this.props.children({ ... })! And it will still work the same way! 👍You can decide which one you want to use. There is always more than one right way to do finish the job!

Conclusion

This was a simple example that could have been implemented in many other ways, but the purpose was to show how Render Props works. I hope you got a better understanding of what Render Props are and how to use them. If you did, try it out for yourself next time you want to make a reusable component! Also if you need better explanations, I recommend you to read the React docs. I think it explains Render Props more in-depth than I did! 😂The docs and codesandbox should be linked at the bottom of this article.

Thank you for your time! Peace! ✌️

Javen

codesandbox.io

Render Props – React