在未安装的组件上调用 setState

IT技术 javascript reactjs promise
2021-04-27 13:41:13

在我的很多组件中,我需要做这样的事情:

handleSubmit() {
  this.setState({loading: true})
  someAsyncFunc()
    .then(() => {
      return this.props.onSuccess()
    })
    .finally(() => this.setState({loading: false}))
}

onSuccess功能

  • 可能是也可能不是Promise(如果是,loading则应保持真实,直到解决)
  • 可能会也可能不会卸载组件(它可能会关闭该组件所在的模式,甚至导航到不同的页面)

如果函数卸载组件,this.setState({loading: false})显然会触发警告Can't call setState (or forceUpdate) on an unmounted component.

我的两个问题:

  1. 有没有一种简单的方法可以避免这个问题?我不想设置一些_isMounted变量componentDidMountcomponentWillUnmount,然后检查它需要在我的大多数组件的时候,再加上我可能会忘记做下一次写这样的事情...
  2. 真的有问题吗?我知道,根据警告,it indicates a memory leak in my application但在这种情况下它不是内存泄漏,是吗?也许忽略警告就可以了......

编辑:第二个问题对我来说比第一个问题更重要一点。如果这真的是一个问题并且我无法调用setState未安装的组件,我可能会自己找到一些解决方法。但我很好奇我是否不能忽略它。

问题的现场示例:

4个回答

不幸的是,您必须自己跟踪“isMounted”。为了简化您的控制流程,您可以使用async/await

handleSubmit() {
  this.setState({loading: true})
  try {
    await someAsyncFunction()
    await this.props.onSuccess()
  } finally {
    if (this._isMounted) {
      this.setState({loading: false})
    }
  }
}

这实际上在react文档中提到,它指向这个解决方案:https : //gist.github.com/bvaughn/982ab689a41097237f6e9860db7ca8d6

如果您someAsyncFunction支持取消,您应该在componentWillUnmount 中这样做,正如本文所鼓励的那样但是然后-当然-检查返回值并最终不调用this.props.onSuccess

class myClass extends Component {
  _isMounted = false;

  constructor(props) {
    super(props);

    this.state = {
      data: [],
    };
  }

  componentDidMount() {
    this._isMounted = true;
    this._getData();
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  _getData() {
    axios.get('example.com').then(data => {
      if (this._isMounted) {
        this.setState({ data })
      }
    });
  }


  render() {
    ...
  }
}

您应该能够用来this._isMounted检查组件是否实际安装。

handleSubmit() {
  this.setState({loading: true})
  someAsyncFunc()
    .then(() => {
      return this.props.onSuccess()
    })
    .finally(() => {
      if (this && this._isMounted) { // check if component is still mounted
        this.setState({loading: false})
      }
    })
}

但请注意,这种方法被认为是一种反模式。https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html

关于什么

componentWillUnmount() {  
    // Assign this.setState to empty function to avoid console warning
    // when this.setState is called on an unmounted component
    this.setState = () => undefined;
}