Functional refs behave different from React
See original GitHub issueI may have discovered a subtle deviation from React’s behavior regarding the dispatch of functional refs.
That is, something like <p ref={ p => doSomething(p) }>
seems to behave different during updates.
I’ve created an sandbox that prints out the sequence of events:
https://codesandbox.io/s/happy-morning-jyu67
You can toggle between react
and preact
by un/commenting the imports at the top of the script.
If I copy the console output from react
and preact
and put them side-by-side (and some empty lines to show the missing events) it looks like this:
The big question for me here is, why is react
dispatching the ref
callbacks with null
for elements that weren’t removed during the update?
Even if I add key
attributes to these elements, I get the null
events.
Now, according to the React docs, it seems to me maybe preact
is actually right on this point:
React will call the ref callback with the DOM element when the component mounts, and call it with
null
when it unmounts.
Of course, this doesn’t say it won’t call the ref callback with null
between updates, but it certainly seems to imply so?
I went back as far as react
16.8.0
, and it behaves like this in every release - unfortunately, older versions than that refuse to load in CodeSandbox, so I can’t say if the behavior was always like this.
I’ve tested with preact
and preact/compat
, both of which behave the same.
Anyhow, bottom line is, if people rely on callbacks with null
as a means of cleaning up side-effects, this could definitely lead to problems, right? (I suspect it might account for some of the reported incompatibilities with various libraries intended for React, but I haven’t looked at those reports/libraries in-depth to see if they use functional refs.)
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (3 by maintainers)
Top GitHub Comments
@JoviDeCroock
After the second render, you should probably assert that
ref
has been called again withnull
.Imagine patterns like this
You want to ensure that the current state of the mutable storage doesn’t leave the DOM node in there forever.
It’s intensional because it’s a new function identity we don’t know if it’s a different ref all together.
If it’s the same referential identity it’s not called.
Seems like Preact wouldn’t handle changes to the ref callback without doing this?