It seems render props have not get enough traction so far, however, it's widely used by prestigious react libraries, like react-router 4
, react motion
etc. And react site also have a dedicated section for it, any reason for this emerged pattern, how is compared to commonly known HOC (high order component) pattern?
The term “render prop” refers to a technique for sharing code between React components using a prop whose value is a function. 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.
HOC , Render Props and now hooks all serve to the same purpose: Share stateful logic between components. There is actually no way to tell which one is better or worst. All depends on your use case. On the other hand, render props it's easy to set up, have less boilerplate and in most cases are easier to reason about.
A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React's compositional nature. Concretely, a higher-order component is a function that takes a component and returns a new component.
The Render Props is a technique in ReactJS for sharing code between React components using a prop whose value is a function. Child component takes render props as a function and calls it instead of implementing its own render logic.
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]
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:
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With