React开发中更新state前是否需要先检查组件是否已挂载?
问题解答
1. 更新state前是否需要确认组件挂载状态
有必要。
如果组件已经被卸载后仍执行setState操作,React会抛出「Can't perform a React state update on an unmounted component」的经典警告,同时还意味着你的异步操作引用没有被及时释放,存在内存泄漏、后台无用资源占用的问题。
尤其是你给出的代码场景里,await asyncOperation()是耗时异步操作,用户完全有可能在请求返回前就退出当前页面/销毁组件,这时候后续的state更新就会触发上述问题。
2. 给出的代码写法是否合理
整体思路正确,但存在2个明显问题:
- 逻辑bug:异步操作结束后的
setIsRefreshing(true)明显是笔误,正常刷新结束后应该把刷新状态重置为false,也就是应该写setIsRefreshing(false),否则刷新状态会一直处于加载中,无法复位。 - 方案不够完善:仅通过
isMounted判断跳过state更新,只是避免了React警告,后台的asyncOperation异步操作仍然会继续执行,还是会占用不必要的网络、计算资源。更推荐的做法是搭配AbortController在组件卸载时直接取消异步请求,从根源上避免后续的state更新逻辑执行:
function UnmountableScreen() { const [isRefreshing, setIsRefreshing] = useState(false); const handleOnRefresh = async () => { const controller = new AbortController(); // 组件卸载时中止请求 const unmountListener = () => controller.abort(); window.addEventListener('beforeunload', unmountListener); setIsRefreshing(true); try { // 把signal传给异步操作,比如fetch的第二个参数 await asyncOperation(controller.signal); setIsRefreshing(false); } catch (err) { // 被中止的请求不需要处理报错 if (err.name !== 'AbortError') { // 其他异常逻辑处理 setIsRefreshing(false); } } finally { window.removeEventListener('beforeunload', unmountListener); } } // ... }
另外要注意useIsMounted的实现要正确,必须基于useRef实现才能保证拿到的始终是最新的挂载状态:
function useIsMounted() { const isMountedRef = useRef(false); useEffect(() => { isMountedRef.current = true; return () => { isMountedRef.current = false; }; }, []); return () => isMountedRef.current; }
内容的提问来源于stack exchange,提问作者Raul
相关产品推荐
相关产品推荐

