1. ホーム
  2. javascript

[解決済み] React - アンマウントされたコンポーネントでの setState()

2023-01-16 11:49:43

質問

私のリアクトコンポーネントでは、ajaxリクエストが進行している間、単純なスピナーを実装しようとしています - 私はロード状態を保存するために状態を使用しています。

何らかの理由で、私のReactコンポーネントの以下のコード片は、このエラーを投げます。

マウントされたコンポーネントまたはマウントされているコンポーネントしか更新できません。これは通常 マウントされていないコンポーネントで setState() を呼び出したことを意味します。これはno-opです。 未定義のコンポーネントのコードを確認してください。

最初のsetStateの呼び出しを取り除くと、エラーは消えます。

constructor(props) {
  super(props);
  this.loadSearches = this.loadSearches.bind(this);

  this.state = {
    loading: false
  }
}

loadSearches() {

  this.setState({
    loading: true,
    searches: []
  });

  console.log('Loading Searches..');

  $.ajax({
    url: this.props.source + '?projectId=' + this.props.projectId,
    dataType: 'json',
    crossDomain: true,
    success: function(data) {
      this.setState({
        loading: false
      });
    }.bind(this),
    error: function(xhr, status, err) {
      console.error(this.props.url, status, err.toString());
      this.setState({
        loading: false
      });
    }.bind(this)
  });
}

componentDidMount() {
  setInterval(this.loadSearches, this.props.pollInterval);
}

render() {

    let searches = this.state.searches || [];


    return (<div>
          <Table striped bordered condensed hover>
          <thead>
            <tr>
              <th>Name</th>
              <th>Submit Date</th>
              <th>Dataset &amp; Datatype</th>
              <th>Results</th>
              <th>Last Downloaded</th>
            </tr>
          </thead>
          {
          searches.map(function(search) {

                let createdDate = moment(search.createdDate, 'X').format("YYYY-MM-DD");
                let downloadedDate = moment(search.downloadedDate, 'X').format("YYYY-MM-DD");
                let records = 0;
                let status = search.status ? search.status.toLowerCase() : ''

                return (
                <tbody key={search.id}>
                  <tr>
                    <td>{search.name}</td>
                    <td>{createdDate}</td>
                    <td>{search.dataset}</td>
                    <td>{records}</td>
                    <td>{downloadedDate}</td>
                  </tr>
                </tbody>
              );
          }
          </Table >
          </div>
      );
  }

問題は、コンポーネントがすでにマウントされているはずなのに、なぜこのエラーが発生するのかということです (componentDidMount から呼び出されているため) 私は、コンポーネントがマウントされたら状態を設定しても安全だと考えていました。

どのように解決するのですか?

レンダー関数を見ることなく、少し厳しいです。すでに何かを見つけることができますが、インターバルを使用するたびに、アンマウント時にそれをクリアするようになった。ということです。

componentDidMount() {
    this.loadInterval = setInterval(this.loadSearches, this.props.pollInterval);
}

componentWillUnmount () {
    this.loadInterval && clearInterval(this.loadInterval);
    this.loadInterval = false;
}

これらの成功やエラーのコールバックはアンマウント後も呼び出されるかもしれないので、interval変数を使ってマウントされているかどうかを確認することができます。

this.loadInterval && this.setState({
    loading: false
});

これでうまくいかない場合は、レンダー関数を提供してください。

乾杯