question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Functional refs behave different from React

See original GitHub issue

I 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:

image

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:closed
  • Created 4 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

4reactions
sebmarkbagecommented, Oct 28, 2019

@JoviDeCroock

After the second render, you should probably assert that ref has been called again with null.

Imagine patterns like this

let ref = useRef(null);
useEffect(() => {
  if (ref.current) doSomething(ref.current);
});
return <div ref={bool ? n => { ref.current = n; } : () => {}} />;

You want to ensure that the current state of the mutable storage doesn’t leave the DOM node in there forever.

3reactions
sebmarkbagecommented, Oct 28, 2019

It’s intensional because it’s a new function identity we don’t know if it’s a different ref all together.

<p ref={
  c ? n => doSomething(n)
  : n => doSomethingElse(n)
} />

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?

Read more comments on GitHub >

github_iconTop Results From Across the Web

A complete guide to React refs - LogRocket Blog
Learn how to use React refs, and why it's important to use them only when React can't handle a function call through its...
Read more >
Refs and the DOM - React
Refs provide a way to access DOM nodes or React elements created in the render method. In the typical React dataflow, props are...
Read more >
Everything You Need to Know About Refs in React
Short for “reference”, refs are a way to access underlying DOM elements in a React component. There are many reasons why you would...
Read more >
How to Use React Refs - Ross Bulat - Medium
React Refs are a useful feature that act as a means to reference a DOM element or a class component from within a...
Read more >
Difference between useRef and createRef in ReactJS
What is a ref ? A ref is defined as any value that does not trigger a component re-render when it is changed....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found