-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Suggestion]: StrictMode confusion about ordering of the events #7315
Comments
@Tosheen, good day! useEffect in StrictMode works a little differently. In StrictMode, the React does mount, unmount, and remount the component again, but useEffect is called at another stage of the React algorithm and it has "its own life", however, it is also called, immediately cleared and called again. This is done in order to properly track the moments when some logic was performed in useEffect, but the user has already left the page where this component was. For example: import { useEffect } from "react";
export default function App() {
useEffect(() => {
const onChange = () => console.log("resize", onChange)
window.addEventListener("resize", onChange)
}, [])
return <div>test</div>
} In this code, we subscribe to the "resize" event, but we don't unsubscribe from it anywhere, and StrictMode, thanks to this "trick", points us to this problem before we could notice it. To solve this problem, we need to modify the following code useEffect(() => {
const onChange = () => console.log("resize", onChange)
window.addEventListener("resize", onChange)
return () => {
window.removeEventListener("resize", onChange)
}
}, []) This also applies to http requests that are sent to useEffect. Strict Mode will call requests twice after all stages of useEffect processing, but this is done for a reason, since there are often cases when the request was sent, but the user has already left the page, the data has returned - but the component is no longer there. To avoid such problems, StrictMode will handle useEffect separately and point out this error by calling the request twice. If you ignore this warning, in the case that I described above, the following problem may appear: To solve this problem, you should use data processing after calling fetch or use an AbortController In conclusion, I want to say that StrictMode also works correctly, and in general does not violate its concept of "first mount" -> "unmount component" -> "second mount", just useEffect is called at another stage of processing the algorithm, which is why with StrictMode, useEffect processing goes at the very end, and with "manual rewire" - in the middle of the process Hope this helps! |
Hi, @pamellix. |
@branko-toshin-deel To be honest, I do not know why the StrictMode logic is implemented in this way, but I assume that this is done in order to optimize the application in dev mode. useEffect starts executing between the second and third stages of React rendering, when the basic manipulations with vDOM and DOM have already been performed. I assume this was done with the intention of not overloading StrictMode's work with unnecessary operations. I think that with StrictMode React, when rendering for the first time, it only works with what changes the DOM, skipping the stages of working with effects. And after the second render, it already fully processes all the effects that are in the component, thereby reducing the load. Roughly speaking, if I understand everything correctly, with StrictMode we have a "one and a half" render (that is, the first render with skipping effects, and the second render with processing effects twice) of the component, and with "manual re-render" - all two re-renders. I also think that the React team did not introduce such a detail into the documentation because the developers pay little attention to it, more precisely, when working with StrictMode, this detail should not ruin the operation of the application, but I will try to make my contribution to the StrictMode documentation in order to describe in detail its logic of operation! P.S. I also assume that this is done so that working with StrictMode feels not just like "two renderers", but like "one, but an extended render". That is, roughly speaking, StrictMode works with each stage separately, and does not just re-render components twice, thereby it retains the primary logic of the React render, with all stages. I guess StrictMode tests the component in stages not the way we think (I use numbers to indicate the stages of rendering)
it tests them like this
(just my guess) |
@pamellix |
@branko-toshin-deel |
@pamellix That would be most appreciated. |
Summary
This thread comes really close to avoid repeating this question again.
However I still have some doubts about the chain of the events in the strict mode.
I will quote the answer which provide the most valuable feedback.
"The mental model for this is that React really does unmount the component, but when re-mounting the component we restore the previously used state instead of starting fresh, the way Fast Refresh does, or some future features will."
But if that's the case why the order of the events(rendering, setting state, effects etc) is different while running in strict mode and outside of it?
Here are the concrete examples:
The second
render
andstate setter
are dimmed out according to the documentation and that's fine. So at least on the surface it appears that react is triggering render function (and state setter) 2 times before moving to the effects.This example has the mental model I have always worked with and which is clear, so I would waste too much time on it since that's how React also behaves on production.
The question is, if react is really performing mounting, unmounting and remounting while is the order different?
To be honest I haven't noticed that this difference is making my code harder to reason about while working with StrictMode.
I would like to know the details, if possible. What does this approach help React achieve that original one does not?
Page
https://react.dev/reference/react/StrictMode
Details
I think it would be helpful to update the page to explain why the behavior in StrictMode is different than simply running mounting, unmounting and mounting again.
The text was updated successfully, but these errors were encountered: