Reputation: 560
Following is the snippet link to codesandbox:
// function getFetchUrl(query) {
// return "https://hn.algolia.com/api/v1/search?query=" + query;
// }
function App() {
const [reactResult, setReactResult] = useState(null);
const [reduxResult, setReduxResult] = useState(null);
function SearchResults() {
// 🔴 Re-triggers all effects on every render
// const getFetchUrl = useCallback((query) => {
// return "https://hn.algolia.com/api/v1/search?query=" + query;
// }, []);
function getFetchUrl(query) {
return "https://hn.algolia.com/api/v1/search?query=" + query;
}
useEffect(() => {
console.log("running effect: 15");
setReactResult(getFetchUrl("react"));
// ... Fetch data and do something ...
// }, [getFetchUrl]); // 🚧 Deps are correct but they change too often
}, [getFetchUrl]);
useEffect(() => {
console.log("running effect: 21");
setReduxResult(getFetchUrl("redux"));
// ... Fetch data and do something ...
// }, [getFetchUrl]); // 🚧 Deps are correct but they change too often
}, [getFetchUrl]);
// ...
}
SearchResults();
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>{reactResult}</h2>
<h2>{reduxResult}</h2>
</div>
);
}
The output in the console is
running effect: 15
running effect: 21
running effect: 15
running effect: 21
I have checked out the this answer, and I get it that the functions get re-defined which causes the useEffect
to run again(for the second time). But I want to clarify one doubt:
When the useEffect
runs for the second time, it calls the stateSetter
functions(which asks React to render the component again).
So shouldn't the above snippet run in an infinite loop?
Example and basic understanding picked up from A Complete Guide to useEffect
Upvotes: 2
Views: 131
Reputation: 138267
Your effects are only triggered when getFetchUrl
changes ... and as it is a memoized callback (that does not get changed) the effects only run once.
Upvotes: 0
Reputation: 1266
When using useState
react is smart enough to skip re-rendering if the state value
hasn't actually changed despite a call to the setState
function. (This is documented at https://reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update)
The example code you have included is slightly different from the linked code pen and will actually result in only a single "set" of console log message.
running effect: 15
running effect: 21
the sequence of events is:
reactResult
and reduxResult
state. This enqueues a re-render.useCallback
with no dependencies which will return the previous value, and therefore the the effects will not run.On the other hand, in your code pen, instead of useCallback
you redefine the callback on each execution, in that case you will get two "sets" of console message:
reactResult
and reduxResult
state. This enqueues a re-render.getFetchUrl
is a local funtion and so is not equal to getFetchUrl
from the previous run. As a result the effects will re-run. However setReactResult
and setReduxResult
are both called with the same value as before, so a re-render will not be triggered.Upvotes: 3