I was walking through some code and came across the following snippet to prevent StrictMode from calling an effect twice. While it's generally not recommended to implement such a feature, I was more confused on why it actually works. See the following:
export const useApiDemo = (param: string) => {
let strictModeRerun = false;
useEffect(() => {
!strictModeRerun && fetchApi(param);
return () => {
strictModeRerun = true;
};
}, [param]);
};
As I understand in strictmode hooks and components get called twice so we can identify any misconfigurations or faulty cleanups. If useApiDemo (or the component it's used in) renders twice, I would assume strictModeRerun
would also be false twice because it's defined inline in the render scope. It is not persisted between renders so I would assume this causes the second run to also call the api. However the api call is only fired once. If I remove the strictModeRerun
the api does fire twice. Why does this actually work?
I was walking through some code and came across the following snippet to prevent StrictMode from calling an effect twice. While it's generally not recommended to implement such a feature, I was more confused on why it actually works. See the following:
export const useApiDemo = (param: string) => {
let strictModeRerun = false;
useEffect(() => {
!strictModeRerun && fetchApi(param);
return () => {
strictModeRerun = true;
};
}, [param]);
};
As I understand in strictmode hooks and components get called twice so we can identify any misconfigurations or faulty cleanups. If useApiDemo (or the component it's used in) renders twice, I would assume strictModeRerun
would also be false twice because it's defined inline in the render scope. It is not persisted between renders so I would assume this causes the second run to also call the api. However the api call is only fired once. If I remove the strictModeRerun
the api does fire twice. Why does this actually work?
1 Answer
Reset to default 1React 18 has a few dev only quirks. The two we are concerned with here are:
- Double rerendering of components.
- Double running of effects.
They are independent. For example:
let renderCount = 0;
export default function ChatRoom() {
let strictModeRerun = false;
// // let strictModeRerun = false;
renderCount++;
console.log("rerender", renderCount);
useEffect(() => {
console.log("connect", strictModeRerun);
let connect = null;
if (!strictModeRerun) {
connection = createConnection(serverUrl, roomId);
connection.connect();
}
return () => {
strictModeRerun = true;
connection?.disconnect();
};
}, []);
return <h1>Welcome to the {roomId} room!</h1>;
}
The output of the above components rendering in the log is:
This proves that first the double render happens. And only after that the effect runs. Anyway the effect is supposed to run right before painting.
Sandbox Link
rerender
is logged twice with both the values of renderCount
. And then the effect run. Since you are setting the value false, it never runs again as you had imagined.