Skip to content
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

useEffect will unpredictable when depends on ref (useRef) #16121

Closed
lihroff opened this issue Jul 12, 2019 · 5 comments
Closed

useEffect will unpredictable when depends on ref (useRef) #16121

lihroff opened this issue Jul 12, 2019 · 5 comments

Comments

@lihroff
Copy link

lihroff commented Jul 12, 2019

Look at this demo
Is there a bug?

What is the current behavior?
When you click the minus button until value to -1, the # 1 effect will not be triggered, but the dependency has changed.

What is the expected behavior?
The # 1 effect will be trigger when the value changes from 0 to -1,just like # 2 effect

@brookslybrand
Copy link

Using ref.current in a dependency array is going to be problematic. @gaearon explains why in this issue: #14387 (comment)

@Aprillion
Copy link

Aprillion commented Jul 14, 2019

It was triggered when the value changed, but the code [ref.current] was executed BEFORE the mutation by ref={ref}, while console.log(ref.current) was executed AFTER (because useEffect is executed after render).

Execution of useEffect(() => console.log(ref.current), [ref.current]) code can be imagined as follows:

1st render: useEffect(() => console.log('num 1'), [null])
2nd render: useEffect(() => console.log('num 0'), [element with num 1])
3rd render: useEffect(() => 'the element did NOT change in previous render', [element with num 0])
4th render: useEffect(() => console.log(null), [null])

@gaearon
Copy link
Collaborator

gaearon commented Jul 15, 2019

This is expected. Dependencies should only include values that participate in top-down React data flow. Such as props, state, and what you calculate from them. Ref containers are fine too (since they can be passed down).

However, it doesn’t make sense to add ref.current as a dependency. For the same reason it doesn’t make sense to add window.myVariable. When it updates, React won’t know about it, and won’t update your component.

In your case, you either want to use state instead. Or, if you want to be notified about <Something ref={ref} /> getting attached and detached (for example, to measure DOM nodes), you want to use a callback ref instead.

https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node

@andreyvolokitin
Copy link

if you want to be notified about <Something ref={ref} /> getting attached and detached (for example, to measure DOM nodes), you want to use a callback ref instead.

Using this pattern, how to know if ref is getting detached? (similar to the behaviour of the function returned from useEffect callback). We can check if node !== null, but it only checks node existence, and it exists before detach as well as after attach. The guide notes that "the callback ref will be called only when the component mounts and unmounts", but how to distinguish between mount and unmout?

@rnarcos
Copy link

rnarcos commented Sep 6, 2021

@gaearon, what about when you have a list of dynamically added refs (say an array of refs for a component's child). How could one create callback refs like is described here?

What my approach looks like now (won't trigger useEffect's deps array):

const childrenCount = React.Children.count(children);
const [childRefs, setChildRefs] = Array.from({ length: childRefs }).map(createRef);

return React.Children.map(children, (child, index) =>
  React.cloneElement(child, {
    ref: childRefs[index],
  })
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants