-
Notifications
You must be signed in to change notification settings - Fork 47.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
Maintaining ref prop through React.cloneElement() #8873
Comments
I think you might have missed this paragraph:
It's unfortunately not very clear, but the point was that if you override However, indeed, it is possible to keep both refs with callbacks. You just need to do it manually. return React.Children.map(this.props.children, child =>
React.cloneElement(child, {
ref: (node) => {
// Keep your own reference
this._input = node;
// Call the original ref, if any
const {ref} = child;
if (typeof ref === 'function') {
ref(node);
}
}
})
); It’s just functions so you can do something and then delegate to the other function. |
Ah great. Yes, I misunderstood the meaning behind |
@gaearon Don't you need to bind the |
Yea I think you're right. You need to. |
Or maybe not. :P I don't remember whether React takes care to call it with the right instance or not. You can try and let me know. |
Tested it to make sure :) Apart from that it works perfectly. Below is the fixed snippet (also added a missing return React.Children.map(this.props.children, child =>
React.cloneElement(child, {
ref: (node) => {
// Keep your own reference
this._input = node;
// Call the original ref, if any
const {ref} = child;
if (typeof ref === 'function') {
ref(node);
}
}
})
); |
Thanks! I fixed it up in my comment so that people don't get confused. |
How does this work - why is |
Because it doesn't behave like a prop. A component can't read its own ref (by design). Just like
Yes. |
current behavior overrides the child's ref. [Read this](facebook/react#8873 (comment)) for more info.
@gaearon Please forgive me if I'm wrong (I have a hard time understanding the code), but that keeps references of the original children (not rendered) and the cloned version, right? The old children is closed over, yes? |
@gaearon has this advice changed in 16.3+? Also, latest React typings do not expose a 'ref' property on a |
bumping this thread, I'm following the advice of this thread by calling the original ref callback in the overriding ref callback but also not seeing the |
The TypeScript typings are maintained by the community over at DefinitelyTyped. If you're missing a property feel free to submit a patch. |
Here's a small update to @gaearon's manual method that also handles return React.Children.map(this.props.children, child =>
React.cloneElement(child, {
ref: (node) => {
// Keep your own reference
this._input = node;
// Call the original ref, if any
const {ref} = child;
if (typeof ref === 'function') {
ref(node);
} else if (ref !== null) {
ref.current = node;
}
}
})
); That's based on what the React internals appear to do: just set the value of |
@eemeli - Can you provide an example of how the ref is applied to the child DOM element in the above scenario? |
@discrete-projects Something like this? When class Wrapper extends React.Component {
_input = null
componentDidUpdate() {
doSomething(this._input)
}
render() {
return React.Children.map(this.props.children, child =>
React.cloneElement(child, {
ref: node => {
this._input = node
const { ref } = child
if (typeof ref === 'function') ref(node)
else if (ref) ref.current = node
}
})
)
}
}
export class Thing extends React.Component {
_ref = React.createRef()
componentDidUpdate() {
doSomethingElse(this._ref.current)
}
render() {
return <Wrapper {...this.props}>
<div id="dom-thing" ref={this._ref} />
</Wrapper>
}
} |
Interesting how we can do such a solution that you suggested @gaearon but also works for both: ref functions and useRef 🙂 Child can pass ref as a function or pass the useRef object and it works as expected with the parent being use useRef internally. |
This creates big issues when trying to only use createRef/useRef, since in this case you're forced to use ref functions, and the rest of the code must also now expect ref's to be functions sometimes. I.e. all forwardRef components can't just set There needs to be a createRef compliant way to achieve this, without using functions. |
React's 0.13 RC suggests that
ref
prop on components pushed throughReact.cloneElement()
will allow for two parents to maintainref
props to the same child.I've tried to replicate this behaviour in a CodePen, but I am not able to maintain two
ref
references to the same child (ie the ancestor component'sref
gets nulled).Here is the jist of the code, working code found here:
Has this behaviour been dropped/never implemented since the above RC? Or am I doing something wrong?
The text was updated successfully, but these errors were encountered: