I came up with the pattern after discovering the issues with render callbacks and before Higher Order Components were common. You can achieve the same result with a Higher Order Component. The only benefit of this approach over an HOC is that you write a regular Component.
To implement the pattern, you make you Component expect a single child for it's `children` prop. Let's assume that the child has a `data` prop which is not set in the parent Component. In render, you return `React.cloneElement(this.props.children, { data: this.state.valueToInject })`.
The value of a Higher Order Component is that you can usually define a map to props function.
So, uh, thanks.
Then, the final example looks like:
<Mouse>
{({ x, y }) => (
<h1>The mouse position is ({x}, {y})</h1>
)}
</Mouse>
[0]: https://discuss.reactjs.org/t/children-as-a-function-render-...I've literally had good developers not understand them until I switched an example from using children to using a render prop, at which point there's a big light bulb moment.
So i'll be sticking with the render prop.
Having a render prop is slightly better but even this escape hatch isn't foolproof and you'll still end up needing things like onClickOutside.
@connect(mapStateToProps, mapDispatchToProps)
class Component extends React.Component { ... }
has a certain elegance to it.However, I personally advise against using `connect()` as a decorator, for several reasons:
- It's still a Stage 2 proposal. Now, the Class Properties syntax isn't final either (currently Stage 3), which the React team (and I) highly recommend using. However, the Class Properties syntax seems to be much more stable, the behavior it's implementing is a lot simpler, and if by chance it happens to change in the future, it should be relatively easy to code-mod (and the React team has said they would release a code-mod if that happens). Meanwhile, the decorators spec has changed several times (including recently), and the Babel plugins have also had to change behavior and implementation over time.
- It obscures the real class definition. The standard advice for testing Redux-connected components is to export the "plain" class separately as a named export, and `export default connect()(MyComponent)`, then import and test the plain version. If you use @connect() as a decorator, the plain version isn't accessible, and testing becomes more difficult.
- Going along with that, I've seen many questions about why defaultProps and propTypes don't work right when @connect() is used, and it's because those get applied to the wrapper component, not the plain component, and thus things don't work the way you would want them to.
I see no advantages to using connect as a decorator. I encourage people to write their mapState functions separately anyway for clarity and testability (instead of inline as an argument to connect), so it's just a matter of moving the line with `connect` elsewhere in the file and changing the syntax slightly.
The render prop pattern will have just as much nesting. Mixins or plain JavaScript class composition have major well-accepted problems. You could just write one big component with all that functionality, but the fact that it would ever be split into layers of HOCs implies that various functionality is being reused (and probably provided by third party libraries).
Could Redux boilerplate be reduced?
First, could you clarify what _you_ mean by "Redux boilerplate" in this case? The phrase gets thrown around frequently, but it means different things to different people. Just yesterday, I tweeted some thoughts on how you can use as much abstraction as you want with Redux, and linked to examples of reusable action creator/reducer logic [0]. I also wrote a pair of blog posts that discuss the intent behind Redux's design [1], and why common usage patterns exist [2].
It's worth noting that React-Redux was originally written using a "render props"-type approach, but was changed to be a Higher-Order Component before it hit 1.0. In fact, there was a thread a month ago that discussed render props-based reimplementations of `connect` [3], and in that thread I linked to several recent examples of people reinventing that wheel as well as prior discussion of why React-Redux wound up as a HOC.
Finally, earlier this year I opened up an issue to discuss ways that we can improve both the "getting started" experience for Redux users, as well as build more powerful abstractions on top of Redux [4]. I'd love more feedback and ideas (and ideally people from the community volunteering to help us make things better).
[0] https://twitter.com/acemarke/status/928453589739155456
[1] http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao...
[2] http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao...
In fact, render as props is more an OOP pattern. You pass render functions as props and you use delegation pattern to pass context. https://en.wikipedia.org/wiki/Delegation_pattern
ReactTrainig maybe should fix react-router-redux to work with redux time travel.