{"action":"created","issue":{"url":"https://api.github.com/repos/reduxjs/react-redux/issues/920","repository_url":"https://api.github.com/repos/reduxjs/react-redux","labels_url":"https://api.github.com/repos/reduxjs/react-redux/issues/920/labels{/name}","comments_url":"https://api.github.com/repos/reduxjs/react-redux/issues/920/comments","events_url":"https://api.github.com/repos/reduxjs/react-redux/issues/920/events","html_url":"https://github.com/reduxjs/react-redux/issues/920","id":311100397,"node_id":"MDU6SXNzdWUzMTExMDAzOTc=","number":920,"title":"Create ReduxConnection component","user":{"login":"Sawtaytoes","id":3948069,"node_id":"MDQ6VXNlcjM5NDgwNjk=","avatar_url":"https://avatars1.githubusercontent.com/u/3948069?v=4","gravatar_id":"","url":"https://api.github.com/users/Sawtaytoes","html_url":"https://github.com/Sawtaytoes","followers_url":"https://api.github.com/users/Sawtaytoes/followers","following_url":"https://api.github.com/users/Sawtaytoes/following{/other_user}","gists_url":"https://api.github.com/users/Sawtaytoes/gists{/gist_id}","starred_url":"https://api.github.com/users/Sawtaytoes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Sawtaytoes/subscriptions","organizations_url":"https://api.github.com/users/Sawtaytoes/orgs","repos_url":"https://api.github.com/users/Sawtaytoes/repos","events_url":"https://api.github.com/users/Sawtaytoes/events{/privacy}","received_events_url":"https://api.github.com/users/Sawtaytoes/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":8,"created_at":"2018-04-04T06:26:26Z","updated_at":"2018-11-21T16:43:11Z","closed_at":"2018-04-04T13:50:29Z","author_association":"NONE","body":"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.\r\n\r\nI'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?\r\n\r\nThis is the current `ReduxConnection` component as I've got it:\r\n\r\n```js\r\nconst ReduxConnection = ({\r\n  children,\r\n  component,\r\n  mapDispatchToProps = null,\r\n  mapStateToProps = null,\r\n  render,\r\n  ...props\r\n}) => (\r\n  React.createElement(\r\n    connect(mapStateToProps, mapDispatchToProps)(\r\n      (component || render || children || throwError)\r\n    ),\r\n    props\r\n  )\r\n)\r\n```\r\n\r\nUnlike 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.\r\n\r\nThe 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.\r\n\r\nAn example usage where this would be beneficial:\r\n```js\r\n<ReduxConnection\r\n  namespace=\"someNamespace\"\r\n  mapStateToProps={loadingStateSelector}\r\n  component={LoadingIndicator}\r\n/>\r\n<ReduxConnection\r\n  namespace=\"someOtherNamespace\"\r\n  mapStateToProps={loadingStateSelector}\r\n  render={({ isLoading }) => (\r\n    <LoadingIndicator isLoading={isLoading}>\r\n      <div>Some Content</div>\r\n    </LoadingIndicator>\r\n  )}\r\n/>\r\n```\r\n\r\nI 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.\r\n\r\nThe ReduxConnection component also solves this issue of exporting both the stateless, unit-testable component and the `connect`-wrapped version like so:\r\n```js\r\n// I dislike doing this but need to for unit testing.\r\nexport LoadingIndicator () => <div />\r\nexport default connect(state => state)(LoadingIndicator)\r\n```\r\n\r\nWhile 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.\r\n\r\nAnother benefit is the ability to compose it like this:\r\n\r\n```js\r\nconst LoadingState = props => (\r\n  <ReduxConnection\r\n    {...props}\r\n    mapStateToProps={loadingStateSelector}\r\n  />\r\n)\r\n\r\nconst LoadingInformation = () => (\r\n  <Fragment>\r\n    <LoadingState\r\n      component={LoadingIndicator}\r\n      namespace=\"someNamespace\"\r\n    />\r\n    <LoadingState\r\n      component={SpecialLoadingIndicator}\r\n      namespace=\"someOtherNamespace\"\r\n    />\r\n  </Fragment>\r\n)\r\n```\r\n\r\nLastly, 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`](https://github.com/quangbuule/extract-hoc) plugin in my Babel plugins. Not ideal. It's a lot easier to just use a React component and bypass this hack entirely.\r\n\r\nHave I shown enough of a case for the addition of a render props version of `connect` or are there still unanswered questions?\r\n\r\nReferences:\r\n- [Use a Render Prop](https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce)\r\n- [Implementation in React Router](https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Route.js)\r\n"},"comment":{"url":"https://api.github.com/repos/reduxjs/react-redux/issues/comments/440733152","html_url":"https://github.com/reduxjs/react-redux/issues/920#issuecomment-440733152","issue_url":"https://api.github.com/repos/reduxjs/react-redux/issues/920","id":440733152,"node_id":"MDEyOklzc3VlQ29tbWVudDQ0MDczMzE1Mg==","user":{"login":"markerikson","id":1128784,"node_id":"MDQ6VXNlcjExMjg3ODQ=","avatar_url":"https://avatars1.githubusercontent.com/u/1128784?v=4","gravatar_id":"","url":"https://api.github.com/users/markerikson","html_url":"https://github.com/markerikson","followers_url":"https://api.github.com/users/markerikson/followers","following_url":"https://api.github.com/users/markerikson/following{/other_user}","gists_url":"https://api.github.com/users/markerikson/gists{/gist_id}","starred_url":"https://api.github.com/users/markerikson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markerikson/subscriptions","organizations_url":"https://api.github.com/users/markerikson/orgs","repos_url":"https://api.github.com/users/markerikson/repos","events_url":"https://api.github.com/users/markerikson/events{/privacy}","received_events_url":"https://api.github.com/users/markerikson/received_events","type":"User","site_admin":false},"created_at":"2018-11-21T16:43:11Z","updated_at":"2018-11-21T16:43:11Z","author_association":"CONTRIBUTOR","body":"@Sawtaytoes : see my latest thoughts on this topic over in #799 ."}}
{"actor":{"display_login":"markerikson"}}