reactjs / react.dev

The React documentation website
https://react.dev/
Creative Commons Attribution 4.0 International
11.02k stars 7.53k forks source link

Better implementation of render props #1241

Open chochihim opened 6 years ago

chochihim commented 6 years ago

This page https://reactjs.org/docs/render-props.html introduces the "render props" pattern with a class Mouse. Its implementation is

render() {
  return (
    <div>
      <h1>Move the mouse around! 1</h1>
      <Mouse render={mouse => <Cat mouse={mouse} />} />
    </div>
  );
}

And its usage is

<Mouse render={mouse => <Cat mouse={mouse} />} />

I find that if we implement it as

render() {
  const { render: Render } = this.props;

  return (
    <div
      style={{ height: 100, border: "1px solid" }}
      onMouseMove={this.handleMouseMove}
    >
      <Render mouse={this.state} />
    </div>
  );
}

Then we can allow the following usage patterns:

<Mouse render={({ mouse }) => <Cat mouse={mouse} />} /> // the original Cat class, 1st pattern

<Mouse render={MediumCat} /> // MediumCat is a function component, 2nd pattern

<Mouse render={BigCat} /> // BigCat is a class component, 3rd pattern

With this implementation, we have a pattern (the first one) which is almost the same as the original render props. Also it allows another two usage patterns (actually the 1st and 2nd patterns are the same).

I have created a codesandbox demo. In the demo, MouseTracker1 is the same as documented while MouseTracker2 is different in implementation of Mouse as I suggested.

I wonder if this is a better implementation of "render props". Any thought?

alexkrolick commented 6 years ago

The advantage of calling the render prop as a function instead of as a component with React.createElement is that the consumer can compose methods inline using anonymous arrow functions without triggering an unmount/mount each time. This is because React uses the function/class name to determine whether a node could be reused.

Here's a Codepen demonstrating different scenarios: https://codepen.io/alexkrolick/pen/WZwMYW

There was some discussion in the original PR for this doc: https://github.com/facebook/react/pull/10741

chochihim commented 6 years ago

@alexkrolick Your Codepen demo is awesome. Thanks for the clarification. I hope your demo is on the document.

Now I know that inline behaviour is an advantage of calling the render prop as a function instead of as a component with React.createElement. I wonder if there is any advantage of the latter over the former.

If React official documents talk about patterns, I think it is better if it can also discuss the pros and cons of each rendering pattern.

alexkrolick commented 5 years ago

In general the function pattern is more flexible because inside a function the consumer is able to do intermediate computations on the prop value, create intermediate variables, transform the prop, and mix the prop in with other props that are in scope inside the render method.