React新手求助:useEffect中抛出的错误未被try-catch捕获该如何解决?
为什么我的try/catch没捕获到“Module not found”错误?
嘿,我帮你排查了下代码,问题其实出在**isMounted的判断时机**上!
你看,现在你把检查data.modInfo === null的逻辑放在了if (isMounted)的代码块里——如果组件在请求完成前就被卸载了(比如用户跳去了其他页面),isMounted会被设为false,这时候这段检查错误的代码根本就不会执行!错误没被抛出,自然进不了catch块,你也就看不到日志了。
问题拆解
- 组件卸载时,
return () => { isMounted = false; }会把isMounted置为false - 如果此时请求刚好完成,
if (isMounted)条件不成立,里面的错误抛出逻辑直接跳过 - 没有错误被抛出,catch块当然不会触发
解决方案
方案1:调整isMounted的判断位置(兼容旧写法)
把数据合法性检查移到isMounted判断外面,确保不管组件是否挂载,只要数据有问题就会抛出错误;同时在catch里也加isMounted判断,避免组件卸载后调用setState触发警告:
useEffect(() => { let isMounted = true; const fetchData = async () => { try { const res = await fetch(url); if (!res.ok) { throw Error("Unable to request data for this resource"); } // 先检查数据合法性,再判断是否更新状态 const data = await res.json(); if (data.modInfo === null) { throw Error("Module not found"); } if (isMounted) { setmodInfo(data.modInfo); setIsLoading(false); setError(null); } } catch(err) { // 组件仍挂载时才更新状态 if (isMounted) { setIsLoading(false); setError(err.message); console.log('err', err.message); } } }; fetchData(); return () => { isMounted = false; }; }, [url]);
方案2:用AbortController替代isMounted(React官方推荐)
isMounted其实是一种过时的写法,React官方更推荐用AbortController来取消未完成的请求,从根源上避免组件卸载后执行后续代码的问题:
useEffect(() => { const controller = new AbortController(); const signal = controller.signal; const fetchData = async () => { try { // 把signal传入fetch,用于取消请求 const res = await fetch(url, { signal }); if (!res.ok) { throw Error("Unable to request data for this resource"); } const data = await res.json(); if (data.modInfo === null) { throw Error("Module not found"); } setmodInfo(data.modInfo); setIsLoading(false); setError(null); } catch(err) { // 忽略组件卸载时取消请求抛出的AbortError if (err.name !== 'AbortError') { setIsLoading(false); setError(err.message); console.log('err', err.message); } } }; fetchData(); // 组件卸载时取消请求 return () => { controller.abort(); }; }, [url]);
这样调整后,不管组件是否挂载,只要数据返回modInfo为null,错误都会被正常抛出并捕获,你就能看到catch里的日志啦~
内容的提问来源于stack exchange,提问作者7tmilp
相关产品推荐
相关产品推荐

