はじめてのReact #18「Ajaxでデータ取得」

  • このエントリーをはてなブックマークに追加
  • LINEで送る
この記事は 2019年1月22日 に書かれたものです

昨今のWebアプリではWebAPI(RESTful API等)をAjaxなどで叩きデータを取得する、もしくはデータを保存するといった行為を日常的に行っているわけですが、今回はAjaxでデータ取得し表示するまでに挑戦してみます。

MonsterView Component

とあるRPGのモンスターの一覧が記録されたJSONファイルをAjaxで取得し、そのままReactで表示するサンプルです。公式ドキュメントの例をちょろっといじったものになります。

サンプル

データファイルです。実際にはサーバ側で動的に出力することが多いと思いますが、今回は静的なファイルで試します。ファイル名はdata.json

{
  "monsters": [
    { "id": 1, "name": "スライム", "hp": 10 },
    { "id": 2, "name": "ドラキー", "hp": 12 },
    { "id": 3, "name": "おおありくい", "hp": 36 }
  ] 
}

実際の処理を行うHTMLです。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>MonsterView</title>
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

  <!-- Don't use this in production: -->
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>

<div id="root"></div>

<script type="text/babel">
class MonsterView extends React.Component {
  constructor(props) {
    super(props);
    this.state ={
      isLoaded: false,
      error: null,
      monsters: []
    }
  }

  componentDidMount() {
    fetch("https://s3-us-west-2.amazonaws.com/blog.katsubemakito.net/static/react1st/18/data.json")
      .then(res => res.json())
      .then(
        (result) => {
          this.setState({
            isLoaded: true,
            monsters: result.monsters
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error: error
          });
        }
      )
  }

  render() {
    if (this.state.error) {
      return <div>Error: {this.state.error.message}</div>;
    }
    else if ( !this.state.isLoaded ) {
      return <div>Loading...</div>;
    }
    else {
      return (
        <ul>
          {this.state.monsters.map( monster => (
            <li key={monster.id}>
              {monster.name} {monster.hp}
            </li>
          ))}
        </ul>
      );
    }
  }
}

ReactDOM.render(
  <MonsterView />,
  document.getElementById('root')
);
</script>
</body>
</html>
- Sponsored Link -

実行結果

解説

いつ通信を行ってるの?

以前、Reactが用意している機能にLifeCycleについて取り上げましたが、今回はその中のcomponentDidMountを利用しています。componentDidMountメソッド内に処理を書いておくと、ComponentがDOMツリーに追加された直後(render()実行直後)に実行されます。

詳細は以前の記事を参照ください。

Fetch APIでJSON取得

componentDidMount内でやってることは非常にシンプルです。
詳細は端折りますが、FetchAPIはReactではなく比較的最近のJSで導入された機能になります。以前はXHR(XMLHttpRequest)を利用していたわけですが、その置き換えですね。Promise対応となりCallback地獄から開放された素敵機能です。

通信に成功しても失敗してもthis.setState()でステートを更新しています。ただし失敗した場合はステートのerrorにエラーメッセージが入ります。

    fetch("https://s3-us-west-2.amazonaws.com/blog.katsubemakito.net/static/react1st/18/data.json")
      .then(res => res.json())
      .then(
        (result) => {
          this.setState({
            isLoaded: true,
            monsters: result.monsters
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error: error
          });
        }
      )

FetchAPIについての詳細は以下を参照ください。

jQuery版

ちなみにReactはViewの機能しか提供されませんので、Ajax周りは他のライブラリと組み合わせることも可能です。例えばjQueryで実装する場合は以下のようになります。

headタグなどでjQueryを読み込みます。

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

componentDidMountをjQueryの$.getJSONに置き換えてみます。$.ajaxでも大丈夫。

  componentDidMount() {
    let url = "https://s3-us-west-2.amazonaws.com/blog.katsubemakito.net/static/react1st/18/data.json";
    $.getJSON(url)
      .done((json)=>{
        this.setState({
            isLoaded: true,
            monsters: json.monsters
          });
      })
      .fail(()=>{
        this.setState({
            isLoaded: true,
            error: {message:`Can not fetch URL: ${url}`}
          });
      });
  }

FetchAPIとあまり変わらないですねw
以下のURLに実際に実行したファイルも置いておきます。

状態に合わせて表示を切り替る

render()はステートの状態にあわせて返却する(表示する)内容を動的に変更しています、エラー時と通信の最中、そして通信に成功したときですね。

  render() {
    if (this.state.error) {
      return <div>Error: {this.state.error.message}</div>;
    }
    else if ( !this.state.isLoaded ) {
      return <div>Loading...</div>;
    }
    else {
      return (
        <ul>
          {this.state.monsters.map( monster => (
            <li key={monster.id}>
              {monster.name} {monster.hp}
            </li>
          ))}
        </ul>
      );
    }
  }

書籍

React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで (NEXT ONE)
穴井 宏幸 石井 直矢 柴田 和祈 三宮 肇
翔泳社
売り上げランキング: 139,067

参考ページ

コメント

コメント欄は休止中です。お問い合わせはこちらからどうぞ。ご質問はTwitterにリプを投げてください。

このブログを応援する

お寄せいただいたお気持ちは全額サーバ代や次の記事を執筆するための原資として活用させていただいております。この記事が参考になった場合などぜひご検討ください。

PayPal(ペイパル)
PayPalで300円支払う
※金額は任意で変更できます。
※100円でも泣いて喜びますw
※住所の入力欄が現れた場合は「no needed」を選択ください
これまでのご協力者さま
- Sponsored Link -

同じカテゴリの記事

旧コメント欄(表示のみ)

※こちらのコメント欄は以前稼働していたものです。現在は新たに書き込むことはできません。ご感想やご質問は記事の下にあるコメント欄をご利用ください。
  1. Reactわかり隊隊員 より:

    初めまして、React(というかjsやHTMLも…)初心者です。

    空の配列として宣言した「monster」にJSONデータをセットしただけで、
    「monster.name」や「monster.hp」のように参照できるのが理解できていません。

    コンパイル時にエラーになるのかと思っていますが、
    取得するJSONデータの構造は別途どこかに定義しておくのでしょうか?

    検討違いの質問になっているかも知れませんが、宜しくお願いします。

    1. 勝部 麻季人 より:

      ブログをご覧いただきありがとうございます。
      おそらくTypeScriptを中心に勉強されていらっしゃるのではないかと思うのですが、このページのサンプルはTSではなく通常のJavaScriptです。そのため人間がコンパイルを行う必要はなく、そのままの状態でWebブラウザ上で実行します。またJavaScriptには変数の型は存在しないため、制約なく自由にデータを代入することができます。(データ型自体は存在しますが、変数にはどのようなデータ型でも未指定で代入可能です)

      お答えになってますでしょうか?よろしくお願いします。

  2. Reactわかり隊隊員 より:

    御返事頂きまして、ありがとうございます。
    ご回答の内容も承知しました。
    恥ずかしながらチュートリアルやサンプルの流用ばかりで、そもそもTypeScriptを使用している自覚すらありませんでした…。
    ただし、個人的にはそういうレベルの質問をしてしまったという事実を理解した事がすごく大きいです。
    ありがとうございました。