React中useEffect重新触发时如何忽略之前未完成的异步副作用?
解决方案
你遇到的是React useEffect异步请求的经典竞态问题,最简洁的实现方式是利用useEffect的清理函数做过期标记,不需要引入额外依赖,代码修改如下:
const MyComp = () => { const [state, setState] = useState(); const [result, setResult] = useState(); useEffect(() => { // 标记当前effect对应的请求是否已过时 let isStale = false; fetchResult(state).then(res => { // 仅当请求未过时的时候更新结果 if (!isStale) setResult(res); }); // 下一次effect触发/组件卸载时,将当前请求标记为过时 return () => isStale = true; }, [state]); return ( <div>{result}</div> ); };
如果你的fetchResult是基于原生fetch封装的,还可以用AbortController直接取消过时请求,进一步节省资源:
const MyComp = () => { const [state, setState] = useState(); const [result, setResult] = useState(); useEffect(() => { const abortController = new AbortController(); fetchResult(state, { signal: abortController.signal }) .then(setResult) .catch(err => { // 过滤请求取消抛出的AbortError if (err.name !== 'AbortError') console.error(err); }); // 下一次effect触发/组件卸载时直接取消当前请求 return () => abortController.abort(); }, [state]); return ( <div>{result}</div> ); };
两种方案都能保证最终result始终是最新state对应的请求结果,不会出现旧请求覆盖新请求返回值的问题。
内容的提问来源于stack exchange,提问作者ttous
相关产品推荐
相关产品推荐

