Code Link: https://codesandbox.io/s/charming-colden-3browz?file=/src/App.js
I just get started with Redux, and I have a slice defined in src/store/sizeSlice.js
, and my redux store is in src/store/store.js
. Now the idea is when the two buttons (addCol
, addRow
) get clicked, they will dispatch actions to increment the global states of the number of rows and columns. I use two useSelector
hooks in App.js
.
Now whenever I click one of the two buttons, there will be four outputs to the console. For example, if I click addRow
, there will always be one console log of selectRow
, and three logs of selectCol
. I know that the useSelector
gets called when the function component, in this case App.js
rerenders. There should only be two outputs (one selectRow
, and one selectCol
), but why is the selector function getting called three times? Especially the button that is related to it (dispatch addCol
action in this case) didn't get clicked?
React can, and will, on occasion "render" the app more than once during the "Render Phase" to compute a diff that should be rendered, i.e. flushed, to the DOM during the "Commit Phase". The "Commit Phase" is what we generally consider to be a React component "rendering", because this is when we see the UI update.
Why is this distinction important?
Note that the entire React Function component body is the "render" method, and the "render" method is called during the "Render Phase" which "may be paused, aborted, or restarted by React". This means React may call the "render" method as many times as it needs to in order to compute a diff during the reconciliation process, i.e. when state updates have been enqueued and are processed.
You are console logging as an unintentional side-effect in the useSelector
hook callback.
These logs should not be confused for the component rerendering or being rendered to the DOM multiple times. The logs are unintentional side-effects of the "Render Phase" which can occur several times.
If you care to log state updates as a result of state update -> render to DOM then move all console logs into a useEffect
hook. The useEffect
hook is for running intentional side-effects. 1 React component render == 1 intentional side-effect.
App example:
function App() {
const col = useSelector(selectCol);
const row = useSelector(selectRow);
useEffect(() => {
console.log("Count:", { col, row });
}, [col, row]);
return (
<div className="container">
<Row />
<Addcolumn />
<Addrow />
</div>
);
}