web-dev-qa-db-ja.com

マウントされていないコンポーネントでsetState(またはforceUpdate)を呼び出すことはできません

コンポーネントが更新された後、サーバーからデータを取得しようとしていますが、どうにかすることができませんでした。私が理解している限り、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;
}

完全なエラー:

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.
22
Nikola

このインスタンスで使用する一般的なパターンは、

componentWillUnmount() {
    this.isCancelled = true;
}

そして、非同期関数が解決するのを待っているコードでは、状態を設定する前にチェックを追加します。

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
        });
    }
}

これにより、アンマウント/アンマウントコンポーネントの状態設定が停止します

46
Steve Vaughan

受け入れられた答えは機能し、コンポーネントレンダリングメソッド(getInitialState、componentWillMount、componentDidMount)で非同期関数を呼び出す問題の有効な回避策です。

しかし、ReduxやFluxなどの状態管理ヘルパーとグローバルストアを使用することをお勧めします。これにより、複数のsetStateの問題を回避できる場合があります。

1
Eliâ Melfior