Render Props  – An Advanced React Pattern

Render Props  – An Advanced React Pattern

Render Props  – An Advanced React Pattern 1000 500 Gobinda Thakur
React Render Props

Source: Google Images

At times I feel it is good to be lazy.

Bill Gates Quote

Source: Google Images

Being a programmer, you always need to find the easiest way to solve a problem, write less and reusable code that another developer can quickly grasp. Currently, UI libraries like react.js, vue.js etc. are the talk of the town because one can write reusable code using these libraries while solving complex UI problems. Development is fast and it makes life easy for everyone.

Design patterns are fairly common and popular. React also has its own set of patterns which aid in writing clean and robust code while keeping it maintainable. We will be exploring these patterns through a series of blogs. First off, we will be starting with Render props which is one of hottest topics in react community. Read on to delve deeper.

What is render props?

As mentioned in the react docs:

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

They say sharing is caring 😉

Sharing is caring

Source: https://giphy.com/gifs/3oEjHRB18anY6ttsc0

In simple words, render props are simply props of a component where you can pass functions. These functions need to return elements, which will be used in rendering the components.

Let’s understand render props first

Render props look like this:

class NameWrapper extends Component {
  state = { 
     name: 'Dan Abramov' 
  };
  render() {
    return this.props.render(this.state.name);
  }
}
const Name = () => (
  <NameWrapper render={name => <h2>Hi, {name}!</h2>} />
);

We are using the Name component where we can pass a prop called render. Here, render is a function and it receives an argument i.e. state “name”.

The babel version of JSX looks like this:

Babel Version of JSX

JSX


Transpiled Version

Transpiled Version

And this is what it says!

Explain transpiled version of JSX

Have you ever checked the babel transpiled version of render props?

Let’s see how “Name” component will look in babel repl:

var Name = function Name() {
 return React.createElement(
        NameWrapper,
       {
         render: function render(name) {
                    return React.createElement(
                            "h2",
                            null,
                            "Hi, ",
                            name,
                            "!"
                    );
               }
         }
     );
};

As you can see, instead of passing down any value to the props i.e. render, we are passing a function here. So, when that function gets called we will get the <h2> element with the message “Hi, Dan Abramov!”.

Post and Comment example

We have posts with title, description and a link to get the comment for that blog. By clicking on “View Comment”, we will get the comments section.

Code snapshot

Below is the code (without using render props):

Here, we have 2 files to check.

  1. Post.js
  2. Comment.js

We have taken help of JSONPlaceholder for fake rest API call. You can use it for testing and prototyping. Try it once. It is awesome!

You can see in both of the files, we have a lot of duplicate code like state object, componentDidMount() and getData(). These objects and methods are doing almost the same thing in <Post/> and <Comment/> components.

Why should we write the same code again and again? Instead of this, we can write some common code which can be shared by both <Post/> and <Comment/> components.

Let’s do that then.

Create a new component “Wrapper”

import React from "react";
import axios from "axios";
class Wrapper extends React.Component {
  state = {
    data: null,
    error: null,
    isLoading: true
  };
getData() {
    axios.get(this.props.link)
      .then(response => {
        this.setState({
          data: response.data,
          isLoading: false
        });
      })
       .catch(error => {
          this.setState({
            error,
            isLoading: false
          });
       });
  }
componentDidMount() {
    this.setState({ isLoading: true }, this.getData());
  }
render() {
    return this.props.render(this.state);
  }
}
export default Wrapper;

As you can see, we have extracted state object, getData() and componentDidMount() from both the components and put it in the Wrapper component. Inside the render of Wrapper component we are calling this.props.render() with an argument state and returning it.

Now, let’s see the render method of Post and Comment components:

Post.js

render() {
  return (
    <Wrapper
      link="https://jsonplaceholder.typicode.com/posts"
      render={({ data, error, isLoading }) => (
        <div>
          <h2>User's Post</h2>
          {error && <p>{error.message}</p>}
          {isLoading ? (
            <h5>Loading....</h5>) : (
            <ul>
              {data.map(post => (
               // Code for posts
              ))}
            </ul>
            )}
           </div>
         )}
        />
    );
 }

Comment.js

render() {
  return (
    <Wrapper
      link={this.props.link}
      render={({ data, error, isLoading }) => (
        <div>
          <h4>Comment</h4>
          {error && <p>{error.message}</p>}
          {isLoading ? (
            <h5>Loading....</h5>) : (
            <div>
              <p className="comment">{data.body}</p>
              <div>
                <span className="by">Commented By:</span>
                <span className="name">{data.name}</span>
              </div>
             </div>
            )}
          </div>
        )}
       />
   );
 }

In the Wrapper component we are passing props called render. It is catching the state arguments and returning an element in which values of these arguments are used.

Here is the solution with render props:

Conclusion

There has been an endless debate in the react community on Higher-Order Components (HoC) vs. Render Props as techniques for sharing concerns and reusing common logic among components. React’s latest context API uses render props. Even Apollo client uses render props. Developers are increasingly accepting render props.

P.S: I have covered the problems with HoC here. Do check it out 🙂

Gobinda Thakur

Fullstack web developer