Reputation: 41
My understanding was that useEffect ran whenever the dependencies in the array were rerendered (or only at the first render in if it's blank) or whenever ANYTHING rerendered if there was no Array.
I also thought the code directly in the function about return (not inside a hook though) i.e. like how you declare variables to hold values of setState, or declared functions, only ran "once" (though i'm not sure when)
However, in the example below, I saw the console.log statement run multuple times, almost in tandem with useEffect. Specifically it seemed that the console.log was running in some weird offsync pattern with useEffect, but I don't understand why it would be running, if my variables aren't being redeclared and such. Like, even if it's on every render, similar to a useEffect with no specified dependencies, wouldn't it then also be reintializing the useState variables and such??
So my questions are
import React, { useState, useEffect } from 'react';
const App = () => {
const [num, setNum] = useState(1);
const [log, setLog] = useState('');
const add = () => {
setNum(num + 1);
};
useEffect(() => {
setLog('useEffect has run-> NUM was rerendered ' + num);
console.log(log)
}, [num]);
// setLog(log + " floating code has run");
console.log('\n FLOATING CODE HAS RUN ' + num);
return (
<>
<button onClick={add}>{num}</button>
<div>{log}</div>
</>
);
};
export default App;
Also I saw What is the difference between useEffect and code in the body of a functional component? to try and answer my first question, but it didn't explain about declarations, only about the functional difference.
Upvotes: 3
Views: 499
Reputation: 709
In response to your questions:
The code in the body of a functional component executes every time the component is rendered (your console.log('\n FLOATING CODE HAS RUN ' + num);
) In contrast, code in a useEffect
fires on the initial render, and then on every render during which the value of one of the elements in the dependency array has changed. In your example, it should run on the first render, and then every time setNum
causes the value of num
to change.
The reason for it executing twice is difficult to determine, but it may not be an issue. It is likely being caused by internal React mechanisms such as 'strict mode', and will not occur in the production build.
No, setLog
should not necessarily execute before the console.log
. React setState
functions are not guaranteed to execute in sequential order. They should not be regarded as synchronous. You have to take this into consideration when designing your component. This is why, when setting a state that is based on a previous state, you need to pass a callback to the 'set' function with the previous state as a parameter. With that in mind, your const add = () => { setNum(num + 1); };
line is incorrect. It should instead be const add = () => { setNum(prevNum => prevNum + 1); };
Upvotes: 1