1. ホーム
  2. reactjs

[解決済み] Reactの子コンポーネントが親の状態を変更した後に更新されない

2022-05-14 13:25:17

質問

私は、様々な子コンポーネントにデータを入力するための素晴らしいApiWrapperコンポーネントを作ろうとしています。私が読んだすべてのものから、これは動作するはずです。 https://jsfiddle.net/vinniejames/m1mesp6z/1/

class ApiWrapper extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      response: {
        "title": 'nothing fetched yet'
      }
    };
  }

  componentDidMount() {
    this._makeApiCall(this.props.endpoint);
  }

  _makeApiCall(endpoint) {
    fetch(endpoint).then(function(response) {
      this.setState({
        response: response
      });
    }.bind(this))
  }

  render() {
    return <Child data = {
      this.state.response
    }
    />;
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: props.data
    };
  }

  render() {
    console.log(this.state.data, 'new data');
    return ( < span > {
      this.state.data.title
    } < /span>);
  };
}

var element = < ApiWrapper endpoint = "https://jsonplaceholder.typicode.com/posts/1" / > ;

ReactDOM.render(
  element,
  document.getElementById('container')
);

しかし、なぜか親の状態が変わっても子コンポーネントは更新されないようです。

何か見落としているのでしょうか?

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

あなたのコードには2つの問題があります。

子コンポーネントの初期状態がpropsから設定されています。

this.state = {
  data: props.data
};

引用元 SOの回答 :

<ブロッククオート

初期状態をコンポーネントに渡すのは prop はアンチパターンです。 というのは getInitialState (この例ではコンストラクタ) メソッドが呼び出されるのは、コンポーネントがレンダリングされる最初の時だけだからです。 メソッドが呼び出されるだけだからです。それ以上呼ばれることはありません。つまり、もしあなたがその コンポーネントを再レンダリングすると 異なる として値を渡すと prop のような異なる値を指定した場合、コンポーネント はそれに応じて反応しません。 コンポーネントは最初にレンダリングされたときの状態を保持するからです。これは非常にエラーになりやすいのです。

ですから、もしそのような状況を避けられないのであれば、理想的な解決策はメソッド componentWillReceiveProps を使用して新しいプロップをリッスンすることです。

以下のコードを子コンポーネントに追加すると、子コンポーネントの再描画に関する問題が解決されます。

componentWillReceiveProps(nextProps) {
  this.setState({ data: nextProps.data });  
}

2つ目の問題は fetch .

_makeApiCall(endpoint) {
  fetch(endpoint)
    .then((response) => response.json())   // ----> you missed this part
    .then((response) => this.setState({ response }));
}

そして、これが動くフィドルです。 https://jsfiddle.net/o8b04mLy/