-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
connect() does not work with React.forwardRef #914
Comments
The fix would be to use
|
(We'd happily take a PR that adds an ESM build to |
Does passing a forwarded ref type also break Edit: (I tried making a PR for this but realized it wasn't very simple.) |
Yes. |
We chatted with @sebmarkbage and he pointed out that if you want to "redirect" ref to some inner component, class MyComponent extends React.Component {
render() {
return <SomeInnerComponent ref={this.props.myForwardedRef} />;
}
}
const ConnectedMyComponent = connect(
mapStateToProps
)(MyComponent);
export default forwardRef((props, ref) =>
<ConnectedMyComponent {...props} myForwardedRef={ref} />
); There is also another scenario in which you might want to point |
So it sounds like the solution is to avoid returning forwarded-ref components from HOCs when they're composed and have the user call it as needed? I'm not totally sure if this example works with the const MyConnectedComponent = _.flow(
connect(mapStateToProps),
myHoc(),
)(({myForwardedRef, ...props}) => <MyComponent ref={props.myForwardedRef} {...props} />);
export default forwardRef((props, ref) =>
<ConnectedMyComponent {...props} myForwardedRef={ref} />
); |
Do we not pass the class MyComponent extends React.Component {
render() {
return <SomeInnerComponent ref={this.props.myForwardedRef} />;
}
}
const ConnectedMyComponent = connect(
mapStateToProps
)(MyComponent);
export default forwardRef((props, ref) =>
<ConnectedMyComponent {...props} ref={ref} />
); |
For a user like me, this sounds ideal. Is this desirable from your perspective? (Redux core maintainers) |
It makes sense to me that React Redux should do this. But it would be a breaking change. |
Again, we already do this. Otherwise, this test would fail along with a few others in that file. Am I missing something? |
Connect is passing all props down. So yes, if the consumer uses The proposal is that connect itself should use class Something extends Component {
focus() { ... }
}
const Connected = connect(Something)(mapStateToProps)
// Later
<Connected ref={inst => inst && inst.focus()} />
If this change was made then the
I'm not sure why it's related. This test doesn't assert anything about whether |
Seems to me like we're starting to pile up a pretty big list of potential breaking changes here, between this and all the other 16.x-related aspects. And |
Sorry, I'm understanding the issue now: The We can definitely look at this with regards to going 16+ only. Is there any sort of polyfill available? |
Yes, this is what I was referring to. I'm willing to take a stab at implementing this if you're interested in merging it in. With regards to the breaking change: Maybe it can be optional? Not sure where would options for connect go, but I can imagine a minority of users preferring to opt out of this new behavior, even with 16.3+. It should be discouraged going forward, but maybe some code out there depends on reading (private) stuff from the connect instance. |
It won't show up on forwardRef((props, ref) => ...) |
I don't think this makes a lot of sense. There's already a lot of surface area. I think it should be the default behavior (but in the next major). |
Fair enough. Maybe a silly approach, but can we check if Edit: Then again React is really easy to upgrade, so maybe it's not worth the effort. |
Started a poll to check into this stuff: https://twitter.com/timdorr/status/988448040750067715 Also, found a polyfill, but it looks pretty young: https://github.com/soupaJ/create-react-ref |
This is not a full polyfill (https://github.com/soupaJ/create-react-ref#caveats). |
I would recommend against using this polyfill for this reason:
The |
Good news, according to my poll, is 90%+ of folks either are at 16.3 or are able to upgrade to it. |
Was literally just about to say that :) Granted, it's a pair of Twitter polls and with only 70-ish results per poll atm, but it's a good indicator. I personally would say we leave 5.x as the "<= 16.2" line, and focus 6.x as the "compat with 16.3" line. (And then we're probably looking at 7.x as the "rewrite to something something async React rendering" line.) |
This just burned me when |
Looks like this is actively impacting users, and #914 (comment) would be an easy backwards-compatible fix. Am I missing something? |
This breaks withTheme of |
We were originally planning to address this as part of the larger React-Redux v6 work, as seen in #995 and #1000 . However, given that this breaks with React 16.6's I don't have time to tackle this one myself right now, but if someone can file a PR, @timdorr and I can figure out the release strategy. |
I'll look into this today at some point. |
#1062 just landed and closes this out. I'll look at packaging it up for release (namely, if react-is still bloats things a lot). Hopefully today, but I an just a mere mortal. |
Overlay is now a HOC, so the ref needs to be restored. See discussion at reduxjs/react-redux#914, which is a related issue; this is the scenario where forwardRef is described as not possible from user code. To work around, this manually stores & gets the Overlay instance. Note: I wasn't able to assert the needed state with enzyme; hence the test renderer.
I was confused on what that exactly means, so I can spare you the research: use |
More specifically, do that only in 6.0+. |
@ywen : yes, I think you are misunderstanding. The entire point of |
Never mind, upgrade to |
Actually, never mind this comment. I just realized that all I did was recreate .getElementById() ... and I know you're supposed to aviod that. Please feel free to delete this if you have a chance. Thanks. Hi - I was a little afraid to comment b/c I might be out of my depth, but in order to get around the errors that I was getting with trying to pass refs to a connected component, I did this work around. Does anyone know if this is okay to do, or if it causes problems under the hood? My app is really simple, but has animations, and this format is working for me so far. Should I not do it this way? In definition of the parent (class) component:
In the render of the parent (class) component:
In the child (functional) component
Helper function:
|
I created a helper function to be used in place of
|
I slightly changed the solution proposed by @evannorton so that it could be drop-in replacement of connect. import { forwardRef } from 'react';
import { connect } from 'react-redux';
const connectAndForwardRef = (
mapStateToProps = null,
mapDispatchToProps = null,
mergeProps = null,
options = {},
) => component => connect(
mapStateToProps,
mapDispatchToProps,
mergeProps,
{
...options,
forwardRef: true,
},
)(forwardRef(component));
const ConnectedMyComponent = connectAndForwardRef(mapStateToProps, mapDispatchToProps)(MyComponent) |
@JLarky : As JLarky suggested passing extra parameter did the trick
|
Specifically, if I compose
connect
with another HOC that usesforwardRef
, the result offorwardRef
(an object) is passed as theWrappedComponent
, which throws an error claiming it should only be a function.Example
The text was updated successfully, but these errors were encountered: