question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Create ReduxConnection component

See original GitHub issue

I’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:closed
  • Created 5 years ago
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
markeriksoncommented, Apr 9, 2018

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.

1reaction
markeriksoncommented, Nov 21, 2018

@Sawtaytoes : see my latest thoughts on this topic over in #799 .

Read more comments on GitHub >

github_iconTop Results From Across the Web

Connect | React Redux
The connect() function connects a React component to a Redux store. It provides its connected component with the pieces of the data it...
Read more >
React Redux connect(): When and how to use it
The React Redux connect() API is used for creating container elements that are connected to the Redux store. The Redux store is derived...
Read more >
Connected Components and Performance - Practical Redux
Redux helps with this by limiting the sub-trees that actually need to re-render. connect generates wrapper components that manage subscriptions to the store ......
Read more >
Use the connect() Function to Pass Redux State to Sub-routes
React uses a component state that can be modified into the component and pass it to the child component as it gets connected...
Read more >
How to test Redux-connected React components
Writing unit tests for Redux-connected React components can be tricky. This article explains how you can create your tests easily without ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found