DEV Community

hiro@
hiro@

Posted on

What Is The Render Props?

I guess you might have heard about Render Props because React team wrote a article in blog like this.

This is really helpful for me to understand how to use render props though, it might be a little bit hard for people to understand how to use it in depth.

So this time, I'm gonna describe how to use Render Props concisely.

Example Code which I will use for describing is here.

2 types of Render props APIs.

I think there are 2 types of APIs which you can use it as a render props.
First case is to use it as a props in props.
Take a look at example.

// src/containers/App/index.jsx

import React, { createContext } from 'react';
import List from '../../Components/List';

const App = () => (
  <List
    apiPath="//dog.ceo/api/breeds/list/all"
    render={
      ({list, isLoading}) => isLoading ? <div>now loading...</div> : <div>Done!</div>
    }/>
)

export default App;

So, as you can see you can use in props as a props.
Key point is here

render={
      ({list, isLoading}) => isLoading ? <div>now loading...</div> : <div>Done!</div>
    }

How do you use arguments like list and isLoading ? the answer is below!

// src/components/List/index.jsx
import React, { Component } from 'react';

export default class List extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [],
      isLoading: false
    }
  }

  fetchApi = async () => {
    const res = await fetch(this.props.apiPath);
    const json = await res.json();

    await this.setState({
      list: json,
      isLoading: false,
    });
  }

  componentDidMount() {
    this.setState({ isLoading: true }, this.fetchApi);
  }

  render() {
    return this.props.render(this.state)
  }
}

Especially, this line.

  render() {
    return this.props.render(this.state)
  }

So, solution is easy, you need to add object as a arguments in this.props.render() in return method which is going to be returned.
You must be remember that list and isLoading arguments are state in List component.

if you add something key and property in state in List component, you can be used property as a argument from state.
of course, if state is changed, arguments params will be changed.

It's not necessary to add state object in this.props.render() function. but I think you would better add state. The more you use it as a render props component or utils, you would better do it.

this.props.children's case

On the other hand, you can make use of other type of render props by using this.props.children() !

Let's take a look at below's example.

// src/containers/ChildRender

import React, { Component } from 'react';
import Counter from '../../Components/Counter';

const ChildRender = () => (
  <Counter>
    {({count, increment, decrement, incrementAsync, incrementAsyncTen}) => (
      <section>
        <div>count: {count}</div>
        <button onClick={increment}>+</button>
        <button onClick={decrement}>-</button>
        <button onClick={incrementAsync}>incrementAsync</button>
        <button onClick={incrementAsyncTen}>incrementAsyncTen</button>
      </section>
    )}
  </Counter>
)

export default ChildRender;

You might understand what's going on.

I guess it's easy for you to take a look at code of Counter component.

// src/components/Counter

import React, { Component, cloneElement, Fragment } from 'react';

export default class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      increment: this.increment,
      decrement: this.decrement,
      incrementAsync: this.incrementAsync,
      incrementAsyncTen: this.incrementAsyncTen
    }
  }

  increment = () => {
    this.setState(state => ({count: ++state.count}))
  }

  decrement = () => {
    this.setState(state => ({count: --state.count}))
  }

  incrementAsyncTen = () => {
    setTimeout(
      () => this.setState(state => ({count: state.count + 10})), 
      1000
    )
  }

  incrementAsync = () => {
    setTimeout(
      () => this.setState(state => ({count: ++state.count})), 
      1000
    )
  }

  render() {
    const { children } = this.props;
    return children({...this.props, ...this.state})
  }
}

This is pretty easy to understand! and I think it looks similar with HOC Pattern.
You would prepare method which you make use of it as a argument from Counter component in Container or somewhere where you use it.

Finally, you need to render this.props.children() ! but, you need to add props and state or object which you want to add in argument!

Thats's it!

If you are interested in these example, again example is here.
please check it out!

Next time, I'm supposed to describe how to use portals API for React.js!

Thank you for reading! haaaaaaaaave a nice day!

Top comments (1)

Collapse
 
jalex profile image
Alex

What do you think about the use of props as 'public class fields' instead be passed to the method super(props) of the constructor as is show in this video??:

https:// egghead.io /lessons/egghead-use-class-components-with-react

hope read your answer :)