What's render props, how is it different from high order components? What's render props, how is it different from high order components? reactjs reactjs

What's render props, how is it different from high order components?


Leave an answer for my research, different answers & discussions are highly welcome!

HOC borrows the concept from High Order Function:

a higher-order function (also functional, functional form or functor) is a function that does at least one of the following:

  • takes one or more functions as arguments (i.e., procedural parameters),
  • returns a function as its result.[disputed – discuss]

HOC

A higher-order component (HOC) is an advanced technique in React for reusing component logic.

Originates from this Gist.

This pattern is about STATIC composition. Core/reusable logic are encapsulated in the HOC, while leaving the moving parts to the component.

Use withRouter from react router as an example:

withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.

// This gets around shouldComponentUpdate

withRouter(connect(...)(MyComponent))

Now you get an enhanced MyComponent back which has the props of { history, match, location, ...connectProps, ...ownProps } passed by the router HOC.

A common approach is to

compose(  connect( ... ),  enhance( ... ),  withRouter( ... ),  lifecycle( ... ),  somethingElse( ... ))(MyComponent);  

The great part is that you can infinitely compose those HOCs with a compose utility to get a final enhanced version of your component, and your component will get knowledge about redux store, react router etc injected from the new component returned by HOC.

The downside of the approach is that:

  1. The behavior of the component is defined before runtime thus lost the power of react's rendering lifecycles, say you can't do something like:

    compose(  this.state.shouldConnect && connect( ... ),  this.state.shouldEnhance && enhance( ... ),  this.state.shouldWithRouter && withRouter( ... ),  ...)(MyComponent); 

    since state/props is not available before your code runs.

  2. Indirection & Naming collisions.

using a HOC with ES6 classes poses many of the same problems that mixins did with createClass, just re-arranged a bit.

HOCs introduce a lot of ceremony due to the fact that they wrap components and create new ones instead of being mixed in to existing components.


Render Props

A render prop is a function prop that a component uses to know what to render.

First adopted by react-motion, early seen in Dan's Gist few weeks before first commit of redux.

This pattern is about DYNAMIC composition. Core/reusable logics stays in the component while the moving parts get passed as a callback prop.

You can create HOCs through render props.

Still use withRouter as an example:

const withRouter = Component => {  const C = props => {    const { wrappedComponentRef, ...remainingProps } = props;    return (      <Route        render={routeComponentProps => (          <Component            {...remainingProps}            {...routeComponentProps}            ref={wrappedComponentRef}          />        )}      />    );  };  ...  return hoistStatics(C, Component);}; 

While the opposite is not true.

<Connect render={connectPropsMergedWithState => {  <Enhance render={enhancePropsMergedWithState => {    <WithRouter render={routerPropsMergedWithState => {      <Lifecycle render={lifecyclePropsMergedWithState => {        <SomethingElse render={somethingElsePropsMergedWithState => {          ...        }/>        ...      }/>      ...    }/>    ...  }/>  ...}/>

Though it might look not so good, it has lots of gains.

  1. It has better explicitness, since we can see what's exactly passed as parameter to the render props.
  2. Because of 1, it saves us from potential props collisions.
  3. It's dynamic, we can pass whatever we like (including state/props) to render props.

The commonly known downside is performance optimization is tricky, since what props to receive is deferred to runtime. And it's probably not a good idea to do any premature optimization, but that might be totally another topic.

If you agreed upon the direction move of react router from 3 to 4, render props might be your jam.

References:

  1. https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce
  2. https://reactrocket.com/post/turn-your-hocs-into-render-prop-components