LoginSignup
2
4

More than 5 years have passed since last update.

Reactで、動作に必要なAjaxデータを非同期にロードする

Posted at

ユーザー操作と非同期的にAjaxでデータを取得するケースもよくありますが、Reactと組み合わせようとしたときに少し悩むこととなりました。

Ajaxロードだけど悩まない例

「ボタンを押す」→「あるJSONデータを取ってくる」→「とってきたJSONデータをもとに、ポップアップウィンドウを開く」というような動作を考えてみます。

シンプルなコンポーネント
class SimpleComponent extends React.Component {

  handleClick = () => {
    fetch('some.json').then(data => {
      // 実際にはもっと複雑な処理だけど、解説のためごく簡単に
      alert(data.str);
    });
  }

  render() {
    return <button onClick={handleClick}>ボタン</button>;
  }
}

この場合、fetchでとってきたデータはそのままthenで処理されるだけなので、Reactとは何も関係せず処理が完結します。

Ajaxロードしたデータを、コンポーネントの「状態」にしたい

とはいえ、この方法では取得したデータが完全にReactの外の世界に置かれたままとなるので、「ロードしたデータをReactの表示の上でも活用したい」とか、「ボタンクリック以外のタイミングでデータの取得を駆動したい」という目的ではうまく使えません。

そして、コンポーネントが状態を持つときはstateに入れるものなので、データはstateに持たせることにしましょう。なお、Promiseはそれ自体の状態が破壊的に変化しますので、stateに直接入れるとうまく動かないことが見込まれます。

doFetch() {
  if(this.getterPromise) return;
  this.getterPromise = fetch('some.json').then(
    data => this.setState({data});
  );
}

Ajaxロードとボタンクリックを連動させる

これでデータを取れるようにはなりますが、ボタンとの同期はまた考えないといけません。

  • ボタンを押したあとにロードが完了した場合→ロード完了の時点でポップアップを表示
  • ロード完了したあとにボタンを押した場合→ボタンを押した時点でポップアップを表示

どうしようか考えたところで、「ボタンを押したときにはフラグだけ立てて、componentDidUpdateでフラグとデータが揃っているかチェック」という形にすることにしました。なお、今後のReactでは非同期でレンダリングを行うこととなるため、componentDidUpdate以外のコールバックは複数回呼ばれうることになる、とのことです。

componentDidUpdate() {
  if(this.state.data && this.state.willShowPopup) {
    alert(this.state.data);
    this.setState({willShowPopup: false});
  }
}

handleClick = () => {
  this.setState({willShowPopup: true});
}

Reactは枠組みがしっかり決まったライブラリですが、その中でも充分なことが可能です。枠をはみ出せば、一気に茨の道となります。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4