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 and useState infinite loop inconsistencies #17688

Closed
joy-void-joy opened this issue Dec 22, 2019 · 3 comments
Closed

useEffect and useState infinite loop inconsistencies #17688

joy-void-joy opened this issue Dec 22, 2019 · 3 comments

Comments

@joy-void-joy
Copy link

joy-void-joy commented Dec 22, 2019

Do you want to request a feature or report a bug?
A bug

What is the current behavior?
When objects are used as dependency for useEffect, they are ignored and cause automatic rerendering. This is problematic when there is useState inside the useEffect, as it creates an infinite loop.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:

https://jsfiddle.net/dv8qrx16/ Objects can be replaced with non-empty ones.
Variations on the problems are noted in comments. The errors can be seen in the console log:
1000 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

What is the expected behavior?
useState should update the state without bugs. Or if that is not feasible, the bug should be consistent, and the error message reflect this case

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
16.12.0
To the best of my knowledge, this was working in 16.9, but I may be mistaken

Potential workaround
For now, I resorted to use useRef instead of useState.

@vkurchatkin
Copy link

This works as expected. Not sure what you are trying to do, but this:

 const a = {};
  React.useEffect(() => {
    // ...
  }, [a])

is essentially the same as omitting dependencies altogether, as a is going to be different on each render.

@joy-void-joy
Copy link
Author

Is this consistent with the fact that

 const a = 1;
  React.useEffect(() => {
    // ...
  }, [a])

Does not change on each render? Or that

  setA(2);

Also works fine?

This problem stems essentially from trying to pass the rest parameter to useEffect like so:

function App({...props}) {
  const [,setA] = React.useState(0)

  React.useEffect(() => {
    setA({})
  }, [props])


  return (
    null
  )
}

Because I do not know the parameters to give my third-party libraries in advance. Object-passing and fetching with this library are also frequent and also trigger this problem without the rest parameter.
In the case of ...props however, I suppose I could use a specific parameter for that

@bvaughn
Copy link
Contributor

bvaughn commented Dec 22, 2019

This is not a bug. If your component creates a new object each time it renders, React will always re-execute the effect (because its inputs have changed).

Use memoization if you want the object to only be recreated when its properties change (see useMemo). Or just pass the properties themselves, e.g.

useEffect(() => {
  // ...
}, [a.foo, a.bar]);

@bvaughn bvaughn closed this as completed Dec 22, 2019
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

3 participants