Create ReduxConnection component
See original GitHub issueI’d like to get away from the HoC connect
method and instead utilize render props. While higher-order component functions are great if you’re composing components in an export, I’d rather use JSX components to compose components instead. This allows for more freedom in how components are rendered and allows for the creation of dumb components that can dynamically listen to various Redux state props as-needed.
I’ve been working on my own component to do just that called ReduxConnection
, but it’s one of those things that probably should be maintained by the react-redux project. Digging through the source code, I found something similar, a Connect
component that exists in connectAdvanced
. If that was exposed somehow, wouldn’t it allow for the same concept I’m referencing?
This is the current ReduxConnection
component as I’ve got it:
const ReduxConnection = ({
children,
component,
mapDispatchToProps = null,
mapStateToProps = null,
render,
...props
}) => (
React.createElement(
connect(mapStateToProps, mapDispatchToProps)(
(component || render || children || throwError)
),
props
)
)
Unlike React Router’s Route
implementation, I can’t manage the different rendering methods for component
, render
, or children
. I personally like the distinction used by React Router and think it’s a good template for other components with render
props. This particular ReduxConnection
component sends components to the connect
HoC regardless of how those props should be handled.
The worst part is I have to be explicit in which props I’m accepting. Right now, I’ve only got it setup with mapStateToProps
and mapStateToDispatch
, but theoretically, it should support all function methods.
An example usage where this would be beneficial:
// `component`
<ReduxConnection
namespace="someNamespace"
mapStateToProps={loadingStateSelector}
component={LoadingIndicator}
/>
// `render`
<ReduxConnection
namespace="someOtherNamespace"
mapStateToProps={loadingStateSelector}
render={({ isLoading }) => (
<LoadingIndicator isLoading={isLoading}>
<div>Some Content</div>
</LoadingIndicator>
)}
/>
I can put these two components side-by-side or in the same parent component without the parent component needing to know any of its children’s state props. This also allows LoadingIndicator
to be stateless, and only stateful when required.
The ReduxConnection component also solves this issue of exporting both the stateless, unit-testable component and the connect
-wrapped version like so:
// I dislike doing this but need to for unit testing.
export LoadingIndicator () => <div />
export default connect(state => state)(LoadingIndicator)
While this doesn’t solve every unit-testing use case, it explicitly defines which props components are actually receiving versus ones they’re grabbing from the ReduxConnection render
prop. With connect
, you have to mix in a bunch of extra props in your PropTypes
which connect
is passing in.
Another benefit is the ability to compose it like this:
const LoadingState = props => (
<ReduxConnection
{...props}
mapStateToProps={loadingStateSelector}
/>
)
const LoadingInformation = () => (
<Fragment>
<LoadingState
component={LoadingIndicator}
namespace="someNamespace"
/>
<LoadingState
component={SpecialLoadingIndicator}
namespace="someOtherNamespace"
/>
</Fragment>
)
Lastly, if you’ve used React Hot Loader, you’ve probably run into higher-order component hot-reload issues before. The way I’ve gotten around that is using the extract-hoc/babel
plugin in my Babel plugins. Not ideal. It’s a lot easier to just use a React component and bypass this hack entirely.
Have I shown enough of a case for the addition of a render props version of connect
or are there still unanswered questions?
References:
Issue Analytics
- State:
- Created 5 years ago
- Comments:9 (4 by maintainers)
Top GitHub Comments
We’re not planning to implement a render-props-based API for v5. However, since we’ll likely have to reconsider the React-Redux API as a whole for v6 to fully take advantage of async rendering, a render props API may be a possibility at that time.
@Sawtaytoes : see my latest thoughts on this topic over in #799 .