let’s look this code:
app.tsx
import "./App.css";
import useHome from './hooks/useHome';
function App() {
useHome();
return <></>;
}
export default App;
hooks/useHome.ts
import { useEffect, useState } from "react";
const query = (): Promise<number> =>
new Promise((resolve) =>
setTimeout(() => {
resolve(1);
}, 1000),
);
const useHome = () => {
const [pageStatus, setPageStatus] = useState<string>("loading");
const [data, setData] = useState<number | null>(null);
const [deps, setDeps] = useState(data);
const queryData = async () => {
setPageStatus("loading");
try {
const pageData = await query();
setData(pageData); // cause second render
setPageStatus("normal"); // cause third render
} catch (e) {
setPageStatus("error");
}
};
useEffect(() => {
queryData();
}, []);
useEffect(() => {
setDeps(data); // cause third render
}, [data]);
console.log("@render"); // total 3 times
return {
deps,
data,
pageStatus,
};
};
export default useHome;
why ‘@render’ only console.log 3 times?
I expected it render 4 times;
render first at init,
render second because of setData
render third because of setPageStatues ( async function environment here )
render forth because of setDeps
but I find it only console 3 times…
Is react merged the setPageStatues and setDeps ?
3
Answers
The console log will trigger each time your component is rerendered. (i.e each time there is a state change in the component)
Additionally initially react will render your component twice in development mode but it will only do it locally and not in production builds.
Your assumption here is mistaken. These don’t each cause a re-render. These queue/batch their respective state updates. When the operation is complete, state updates are performed and the component re-renders.
The answer to your question is: React’s batch update mechanism
Inside queryData, you first set the pageStatus to "loading", which queues a state update.(not doing it immediately, just queue it)
You then await query() which resolves after 1 second.
After query() resolves, setData is called, queuing another state update.
Immediately after setting data, you set pageStatus to "normal", queuing yet another state update.
So here in such scenarios, React intelligently batches these updates into a single render cycle. Therefore, these changes result in just one render instead of separate renders.