React移除组件后setState的报错处理

有些时候,我们想在请求后再去更新组件的状态从而更新UI,比如删除一个列表的某一个项。
整个流程就是用户先点击按钮,按钮发起删除请求api,api发送成功后执行回调,回调里面执行state的更改,从而从新渲染页面。
若获得响应时,组件已经被移除,则会导致互相引用,React 抛出一个错误,告诉你这样会导致内存溢出。

index.js:1 Warning: Can't perform a React state update on an unmounted component. 
This is a no-op, but it indicates a memory leak in your application. 
To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method

我们可以利用全局的事件分发和监听机制避免解决这个问题

父组件

import React, { Component } from "react";
import AfterUnmountSetState from './AfterUnmountSetState';
export default class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      isShow: true
    }
  }
  componentDidMount() {
    setTimeout(() => {
      this.setState({
        isShow: false
      })
    }, 3000) // 假设3秒后移除组件
  }

  render() {
    return <div>
      {this.state.isShow && <AfterUnmountSetState></AfterUnmountSetState>}
    </div>;
  }
}

子组件

import React, { Component } from "react";

export default class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      data: 1
    }
    this.eventName = 'AfterUnmountSetState'
    this.query = this.query.bind(this)
    this.handleChange = this.handleChange.bind(this)
  }
  query() {
    console.log('发送了请求')
    // 模拟请求
    setTimeout(()=> {
      // 发送请求后通知操作数据更新ui,使用全局通知。而不是直接操作ui。
      const event = new Event(this.eventName);
      // 也可实用传递参数的自定义事件
      // const event = new CustomEvent(this.eventName, {'detail': {your_data: '...'})
      // e.detail
      window.dispatchEvent(event);
    }, 2000) // 假设请求阻塞花了2秒。
    // 点击多次的时候发送多次请求,也分发出事件给window,让window来代理处理state更新函数。
    // 如果你去除这个部分,则当父组件移除子组件时,会出现报错提醒。
  }
  handleChange() {
    this.setState({
      data: this.state.data + 1
    })
  }
  componentDidMount() {
    console.log('加载完毕监听请求事件')
    window.addEventListener(this.eventName, this.handleChange);
  }
  componentWillUnmount() {
      console.log('卸载前取消监听请求事件')
      // 移除删除监听
      window.removeEventListener(this.eventName, this.handleChange);
  }

  render() {
    return <div>
      {this.state.data}
      <button onClick={this.query}>请求</button>
    </div>;
  }
}

这种做法只适合当父组件可能移除子组件并且子组件内部还有状态需要延迟处理的情况。主要是避免更新状态时已经没有该组件导致报错。

React中,当使用setState方法时出现TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))错误的原因通常是因为你将一个非迭代对象传递给了setState方法。通常情况下,这是由于在使用useState或useReducer时,将初始状态设置为了一个非迭代对象,例如null、undefined或数字。在你提供的引用中,错误发生在useState的初始化中。 正确的写法是将初始状态设置为一个合适的迭代对象。例如,你可以使用一个空数组作为初始状态: const [age, setAge] = useState([]) 或者,你可以根据你的需求设置初始状态为一个有意义的值,比如一个空对象{}。 根据你提供的代码示例,你可以更改List组件中的useState初始化为正确的形式: const [age, setAge] = useState(18) 这样就能避免报错了。记得在使用useState时,仔细检查初始状态的值,确保它是一个迭代对象,而不是一个非迭代对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [TypeError undefined is not iterable (cannot read property Symbol(Symbol.iterator))](https://blog.csdn.net/m0_59092234/article/details/123431518)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值