As far as I can understand, this is a bug.
What is the current behavior?
I have a simple app created with the CLI. I replaced the App.js file by the following:
import React, { useEffect, useState } from "react";
import "./App.css";
const App = () => {
const [value1, setValue1] = useState("default value1");
const [value2, setValue2] = useState("default value2");
useEffect(() => {
setTimeout(() => {
setValue1("done waiting for value1");
}, 1000);
});
useEffect(() => {
setTimeout(() => {
setValue2("done waiting for value2");
}, 2000);
});
/* // this infinitely tries to load /test hence CPU usage too
useEffect(() => {
fetch("/test").then(() => setValue1("done waiting for value1"));
});
useEffect(() => {
fetch("/test").then(() => setValue2("done waiting for value2"));
});
*/
return (
<div className="App">
<p>value 1: {value1}</p>
<p>value 2: {value2}</p>
</div>
);
};
export default App;
Upgrade to @next both react and react-dom. Then run this with npm start.
On both my linux machines I see:

Firefox starts eating 100% of CPU after a small amount of time. Chromium does the same.
What is the expected behavior?
I expect that my CPU usage stays low.
Obviously I could test the value of my value1and value2 to not perform the operation if different than the default value but that might be complicated in some cases.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
"react": "16.7.0-alpha.0",
"react-dom": "16.7.0-alpha.0",
firefox 63.0
Chromium 70.0.3538.77
Ubuntu 18.04
OK, this does seem expected. Effects run after every render by default. You're scheduling an update from an effect. That update leads to render, making effects run again...
We should probably warn about such an "infinite async loop".
The fix is to provide a second argument to useEffect. For example, if you only want to run them once, you can provide []. If you want to run an effect when some value (e.g. value1) changes, you can specify [value1]. See https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects.
ooooh, I didn't caught the empty array trick!
Silly me, I didn't read the note at the end of the useEffect documentation.
PS: I definitely like to dev with hooks. Way leaner and easier to read then some HoC spaghetti I've seen.
OK, this does seem _expected_. Effects run after every render by default. You're scheduling an update from an effect. That update leads to render, making effects run again...
We should probably warn about such an "infinite async loop".
The fix is to provide a second argument to
useEffect. For example, if you only want to run them once, you can provide[]. If you want to run an effect when some value (e.g.value1) changes, you can specify[value1]. See https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects.
This should be made more obvious in the document as there is a lot of use cases that will update states in useEffectHooks, such as fetch data when component mounted.
Most helpful comment
OK, this does seem expected. Effects run after every render by default. You're scheduling an update from an effect. That update leads to render, making effects run again...
We should probably warn about such an "infinite async loop".
The fix is to provide a second argument to
useEffect. For example, if you only want to run them once, you can provide[]. If you want to run an effect when some value (e.g.value1) changes, you can specify[value1]. See https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects.