Working of React in Strict Mode is quite complicated. Clarifying some concepts here.
As per my understanding, in Strict Mode during initial render, React renders a component two times for:
In Strict Mode, React will call your component function twice in order to help you find accidental impurities. This is development-only behavior and does not affect production. Each ref object will be created twice, but one of the versions will be discarded.
Following which one render is committed to the browser DOM. After commit to browser DOM, which is mounting, the Effect is run once. By the new React 18 feature, the component is unmounted (deleted from the browser DOM). Any cleanup mentioned in the Effect is ran. After unmounting, the component is again committed to the browser DOM from the virtual DOM which is remounting. This remounting process does not cause a re-render nor it is triggered by a re-render. It is simply reconciliation from the virtual DOM to the browser DOM. Since the component is committed again to the browser DOM, the useEffect runs again.
During this unmounting and remounting, diffing which is comparing newly rendered virtual DOM and old virtual DOM is not done. Because the component is present in the virtual DOM still now, new rendering for the component is not done, as reference variable still holds value in between mount, unmount and remount.
For subsequent re-renders after the initial render, the component is rendered twice but is committed(mounted) only once. Hence useEffect is being run once.
Also in subsequent renders or in complete unmounting of the component, if cleanup is ran, React uses state values(which is a primitive type) from the previous render(snapshot) whereas takes values of reference variable from the current render (which is a reference type).
During this unmounting and remounting, diffing which is comparing newly rendered virtual DOM and old virtual DOM is not done. Because the component is present in the virtual DOM still now, new rendering for the component is not done, as reference variable still holds value in between mount, unmount and remount.
Is there anything I am missing or any loopholes to my understanding?