如何在componentWillUnmount中取消fetch请求?
解决React组件卸载后调用setState的警告问题
嘿,这个问题我太熟悉了!本质就是组件已经从DOM里卸载了,但之前发起的fetch请求还没完成,等请求结束后去调用setState,React就会抛出那个黄色警告:
Can't call setState (or forceUpdate ) on an unmounted component. This is a no-op, but ...
按照React的提示,我们需要在组件卸载时清理这些异步任务,下面给你两种实用的解决方案:
方案一:用挂载状态标志位做防御检查
我们可以在组件里加个标志位,记录组件是否还处于挂载状态,在fetch的回调里先检查这个标志位,再决定要不要更新状态:
constructor(props){ super(props); this.state = { isLoading: true, dataSource: [{ name: 'loading...', id: 'loading', }] }; // 初始化:组件已挂载 this.isComponentMounted = true; } componentDidMount(){ fetch('LINK HERE') .then(res => res.json()) .then(data => { // 先确认组件还挂载着,再更新状态 if (this.isComponentMounted) { this.setState({ isLoading: false, dataSource: data }); } }) .catch(err => { if (this.isComponentMounted) { this.setState({ isLoading: false }); console.error('请求失败:', err); } }); } componentWillUnmount(){ // 组件卸载时,把标志位设为false this.isComponentMounted = false; }
方案二:用AbortController直接取消请求(推荐)
这个是更优雅的方案,直接在组件卸载时终止fetch请求,从根源上避免后续的回调执行:
constructor(props){ super(props); this.state = { isLoading: true, dataSource: [{ name: 'loading...', id: 'loading', }] }; // 创建AbortController实例 this.abortController = new AbortController(); } componentDidMount(){ fetch('LINK HERE', { // 把控制器的信号传给fetch signal: this.abortController.signal }) .then(res => res.json()) .then(data => { this.setState({ isLoading: false, dataSource: data }); }) .catch(err => { // 捕获请求被取消的错误,不用在控制台输出干扰信息 if (err.name !== 'AbortError') { this.setState({ isLoading: false }); console.error('请求失败:', err); } }); } componentWillUnmount(){ // 取消正在进行的fetch请求 this.abortController.abort(); }
小提示
- 方案一属于“事后补救”,请求还是会跑完,只是不更新状态;方案二则是直接终止请求,更节省资源。
- 如果你用的是axios这类库,也有对应的取消机制(比如axios的CancelToken),思路是一样的。
内容的提问来源于stack exchange,提问作者João Belo
相关产品推荐
相关产品推荐

