React Native中useEffect的正确使用方式:解决组件卸载后更新未挂载组件状态的警告
The warning "Can't perform a React state update on an unmounted component" pops up because your async function getPerMonthCharges might finish executing after the OwnerView component has been unmounted from the DOM. When that happens, calling setMonthlyCharge tries to update state on a component that no longer exists—React flags this as an unnecessary, risky operation.
In your current code, the useEffect runs once when the component mounts, but there's no mechanism to stop or ignore the async function's state update if the component unmounts before the operation completes.
We can add a mounted flag inside the useEffect to track whether the component is still mounted. If the component unmounts before the async operation finishes, we'll skip updating the state entirely. Here's the corrected code:
const OwnerView = () => { const [monthlyCharge, setMonthlyCharge] = useState(0); useEffect(() => { // Flag to track if the component is still mounted let isMounted = true; async function getPerMonthCharges(ownerPhoneNumber, noOfCars) { console.log(`inside getPerMonthCharges`); try { const serviceProviderChargesDoc = await firestore() .collection(`${serviceProviderId}_charges`) .doc(`${ownerPhoneNumber}`) .get(); // Only update state if the component is still mounted if (isMounted && serviceProviderChargesDoc?.data()?.chargesPerMonth > 0) { setMonthlyCharge(serviceProviderChargesDoc?.data()?.chargesPerMonth); return; } } catch (error) { console.log(`Error while fetching monthly charge ${error}`); } // Only update state if the component is still mounted if (isMounted) { setMonthlyCharge(noOfCars * perMonthGeneralCharge); } console.log(`done with getPerMonthCharges`); } getPerMonthCharges(ownerPhoneNumber, vehicles.length); // Cleanup function: runs when the component unmounts return () => { isMounted = false; }; }, []); // Empty dependency array means this runs once on mount // Rest of your component logic... };
- Mounted Flag: The
isMountedvariable stays in scope for the async function, letting us check if the component is still alive before updating state. - Cleanup Function: The
return () => { isMounted = false; }runs automatically when the component unmounts. It flips the flag to false, so any pending state updates are skipped. - Guard Clauses: Before every
setMonthlyChargecall, we check ifisMountedis true. This ensures we never try to update state on an unmounted component.
If you were using fetch instead of Firestore's SDK, you could use an AbortController to cancel the network request entirely when the component unmounts. However, Firestore's get() method doesn't support aborting directly, so the mounted flag approach is the most reliable solution here.
内容的提问来源于stack exchange,提问作者Tarun Chawla

