
Redux Connector – Connect to redux state from within your JSX - juliankrispel
https://www.npmjs.com/package/redux-connector
======
acemarke
A lot of people seem to be re-discovering and re-inventing this approach, due
to the recent discussions in the React community about the use of "render
props" as an alternative to Higher-Order Components. It's interesting to note
that this is actually how React-Redux worked originally [0], but it was
changed to be a HOC later.

There's other recent examples at [1] and [2]. Dan Abramov's tweet at [3]
describes why React-Redux changed from a render prop to a HOC in the first
place, and there's another good Twitter discussion thread at [4] (where
Michael Jackson points out that this is suddenly a really popular thing to
try).

Glancing at the source code for this implementation, I'm actually rather
concerned about its performance. It looks like it calls `connect()` _inside_
of a functional component. That means that every time React re-renders the
parent functional component, `connect()` will generate a new HOC component,
React will see that it's a different component type being rendered (because
the new HOC is not the same as the old HOC), and the entire child component
tree will be thrown away by the reconciliation process. This does not seem
like a very performant approach.

[0] [https://github.com/reactjs/react-
redux/tree/11adf721fbb3f554...](https://github.com/reactjs/react-
redux/tree/11adf721fbb3f5548c6e5f6b4999835d41807850#deprecated-api)

[1] [https://github.com/jsonnull/redux-
render](https://github.com/jsonnull/redux-render)

[2] [https://medium.com/@gott/connecting-react-component-to-
redux...](https://medium.com/@gott/connecting-react-component-to-redux-store-
with-render-callback-53fd044bb42b)

[3]
[https://twitter.com/dan_abramov/status/913712295594926080](https://twitter.com/dan_abramov/status/913712295594926080)

[4]
[https://twitter.com/mjackson/status/915335846324092930](https://twitter.com/mjackson/status/915335846324092930)

~~~
amk_
I have to agree, this will create a new component type every time the function
is called, definitely causing a repaint and re-render of the subtree.

The "right" way to do this is re-implement `connect` as a render-callback and
then use that to create a HOC, not the other way around.

[https://github.com/juliankrispel/redux-
connector/blob/master...](https://github.com/juliankrispel/redux-
connector/blob/master/src/index.js#L14-L18)

Here's a Codepen that demonstrates which component-creation methods are safely
inlineable and which aren't:

[https://codepen.io/alexkrolick/pen/WZwMYW](https://codepen.io/alexkrolick/pen/WZwMYW)

GIF of repaints: [https://user-
images.githubusercontent.com/1571667/30631908-f...](https://user-
images.githubusercontent.com/1571667/30631908-f044d696-9d9a-11e7-8582-1ab3dfcbb8c3.gif)

------
savanaly
The rationale sections reads:

>Higher order components are used to wrap other components. This component
enables you to use connect straightforwardly within jsx, removing much of the
cognitive burden of using connect and refactoring components to use connect.

I don't understand the rationale after reading that though. An example of the
cognitive burden of rewriting a component to use connect would be appreciated.
I write components using the connect HOC all day at work and have never felt
any cognitive burden.

By the way, I always use decorator syntax to apply HOC's to my components, and
perhaps that is why I don't think it's hard to parse at all? For example:

    
    
      @connect(mapStateToProps, mapDispatchToProps)
      class MyComponent extends React.Component {
        // etc.
      }
    
      export default MyComponent;

~~~
acemarke
FWIW, both the React and Redux teams generally advise against the use of
decorators, and I personally heavily advise against using `connect` as a
decorator, for several reasons:

\- It's still a Stage 2 proposal. Now, the Class Properties syntax, which the
React team (and I) highly recommend using, is also not yet final (it recently
advanced to Stage 3). 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 some already, including
at a recent TC39 meeting, 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.

~~~
savanaly
Thanks for the well thought out response. Your second point about class
definitions and ease of testing is making me reconsider my using decorators
for HOC's.

To your first point, I would say the HOC's as decorators would be very easy to
code mod as well. Just go to ever file with decorators on my components and
rewrite it to use _.fp.pipe() or apply them longhand or whatever. It probably
couldn't comfortably be done in an automated fashion but it would be
straightforward and not require a lot of thought.

And to the third point I have never had those not work right when using
connect. I would be interested in an example even if it's just a stack
overflow question where it came up.

~~~
acemarke
As a real quick example, purely off the top of my head:

    
    
        @connect(state => ({a : state.a})
        class MyComponent extends React.Component {}
    
        MyComponent.propTypes = {a : PropTypes.string.required, b : PropTypes.number.required}
        MyComponent.defaultProps = {b : 42}
    

In this example, both the propTypes and defaultProps definitions are being
applied to the wrapper component, not the actual "plain" MyComponent class.
So, while the required `b` prop might get satisfied almost accidentally from
the defaultProps value, the required `a` prop won't exist on the wrapper, as
the wrapper itself is extracting that value from the Redux state internally
and passing it to the plain MyComponent.

I've definitely seen this pop up as a recurring question that's confused
people.

~~~
savanaly
Ah. That has never come up for me because I assign `propTypes` and
`defaultProps` within the class definition using class properties. I had
assumed you would be assuming I would too because you made mention of class
properties in your post. Who would go to the trouble of setting up decorators
without also using class properties syntax? Quite a few people, apparently,
but the practice of using one and not the other baffles me.

~~~
acemarke
Yeah, I actually wasn't 100% sure whether class properties + a decorator would
play together as "expected". Thinking about it, I would guess they must, in
which case defining those values as class properties also would be reasonable.

------
thatswrong0
Mildly related - can we talk about the idiomatic way of focusing components
with HoCs? I feel like I haven’t read anything about a settled convention - I
know I could pass a focus prop and check to see if it’s changed in order to
focus a child component, but it seems a bit heavy handed when I know I just
want to focus the child of an HoC. _Some_ 3rd party HoCs I’ve used expose
something like an “instance()” method that lets me access the child component
via a ref, but of course some HoCs don’t.

------
williamdclt
Not a fan at all. First I'm not convinced by render props: it allows
factorization, but I'd rather have the "wrapping" happen outside of the
component (like the HoC pattern does) than inside the render().

But even more: this could be useful for connect()ing different parts of your
component independently, but having this need is a _huge_ hint that you should
split your component.

~~~
simplysh
I agree with you, this is in no way clearer than exporting a connected
component, in fact I find it harder to parse. Really, I don't see any
advantage in doing things this way.

------
kiliancs
It will also add an additional level to the node tree, I think.

Additionally, connect from react-redux seems to provide a better API for the
common case where you want to export both the bare and the connected versions
of a component.

