Javascript 无法在未安装的组件上调用 setState(或 forceUpdate)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/50428842/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:36:38  来源:igfitidea点击:

Can't call setState (or forceUpdate) on an unmounted component

javascriptreactjsreact-lifecycle

提问by Nikola Stojakovi?

I'm trying to fetch the data from the server after component has been updated but I couldn't manage to do that. As far as I understand componentWillUnmountis called when component is about to be destroyed, but I never need to destroy it so it's useless to me. What would be solution for this? When I should set the state?

我试图在组件更新后从服务器获取数据,但我无法做到这一点。据我所知componentWillUnmount,在组件即将被销毁时调用,但我从来不需要销毁它,所以它对我没用。对此有什么解决方案?我应该什么时候设置状态?

async componentDidUpdate(prevProps, prevState) {
  if (this.props.subject.length && prevProps.subject !== this.props.subject) {
    let result = await this.getGrades({
      student: this.props.id,
      subject: this.props.subject
    });
    this.setState({
      subject: this.props.subject,
      grades: result
    });
  }
}

async getGrades(params) {
  let response, body;

  if (params['subject'].length) {
    response = await fetch(apiRequestString.gradesBySubject(params));
    body = await response.json();
  } else {
    response = await fetch(apiRequestString.grades(params));
    body = await response.json();
  }

  if (response.status !== 200) throw Error(body.message);

  return body;
}

Full error:

完整错误:

Warning: Can't call setState (or forceUpdate) 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.

回答by Steve Vaughan

A common pattern I use in this instance is something along the lines of

我在这个例子中使用的一个常见模式是

componentWillUnmount() {
    this.isCancelled = true;
}

And then in the code where you're awaiting an async function to resolve, you would add a check before setting state:

然后在等待异步函数解析的代码中,您将在设置状态之前添加检查:

async componentDidUpdate(prevProps, prevState) {
    if (this.props.subject.length && prevProps.subject !== this.props.subject) {
        let result = await this.getGrades({
            student: this.props.id,
            subject: this.props.subject
        });
        !this.isCancelled && this.setState({
            subject: this.props.subject,
            grades: result
        });
    }
}

That will stop any state setting on unmounted/unmounting components

这将停止卸载/卸载组件的任何状态设置

回答by Elia Melfior

The accepted answer works, and is a valid workaround for the problem of calling asynchronous functions in the component rendering methods (getInitialState, componentWillMount, componentDidMount).

接受的答案有效,并且是在组件呈现方法(getInitialState、componentWillMount、componentDidMount)中调用异步函数的问题的有效解决方法。

But a better practice would be to use state management helpers like Redux and Flux and a global store, this might avoid the problem of multiple setStates.

但更好的做法是使用 Redux 和 Flux 等状态管理助手和全局存储,这可能会避免多个 setState 的问题。