プログラミング

React + TypeScriptで都道府県情報をAPIで取得してグラフ表示させてみた

  • ReactとTypeScriptのサンプル実装をしてみたい
  • 簡単なコード解説付きでプログラミングをしてみたい
  • とにかく動くものを作りたい
  • プログラミング入門〜初学者

今回はこういった疑問について解説していきます。

この記事を読んだ後

  • ReactとTypeScriptを使ったSPA実装ができる
  • API情報の取得方法を理解できる
  • 簡単なロジック実装をすることができる

それでは具体的にそれぞれ解説していきます

React + TypeScriptを使ってSPAを作る

私は普段AIのサービス開発会社でフロントエンドエンジニアとして働いています。

そこではVue.js, Nuxt.js, TypeScriptを使って開発してますが、今回はReactの勉強も兼ねてReact+TypeScriptで都道府県のAPI情報を取ってきながら簡単なSPAを実装をしてみようと思いました。

まだまだしがないフロントエンドエンジニアでありコードを保証するものではないためその点をご了承の上見ていただけますと幸いです。

実際に作成したリポジトリはこちら
https://github.com/chanten1152/prefectures

 

開発環境と用意するライブラリ

用意するもの・環境

※各ライブラリなどのインストールは実装中に都度紹介します。

  • VSCode
  • react:18.2.0
  • TypeScript:5.0.4
  • axios:1.4.0
  • eslint:8.40.0
  • prettier:2.8.8
  • sass:1.62.1
  • highcharts:11.0.0
  • highcharts-react-official:3.2.0

「都道府県人口推移グラフ」の実装手順とソースコード

では早速実装していきます。

手順は下記の通りに行なっていきます。

  • 環境構築
  • ライブラリのインストール
  • ソースコード
  • API情報の取得と都道府県一覧の表示
  • サンプルデータを入れてグラフの表示
  • クリックとグラフ表示を連動させる
  • スタイル調整

環境構築

はじめにリポジトリを作成します。

Git のマイページからリポジトリのページに移動します。

右上の「New」から新規作成します。

任意の名前をつけます。

作成されたらURLが表示されるのでコピーします。

VSCodeに移動しターミナルを起動します。

git clone URLでリポジトリを取り込みます。

cd リポジトリ名 でディレクトリ移動します。

npx create-react-app prefecture-data --template typescript

コマンドを入力して、開発環境を作成します。

cd prefecture-data でプロジェクトフォルダに移動します。

ライブラリのインストール

各ライブラリを取得していきます。

  • npm install -save highcharts-react-official highcharts
  • npm install axios
  • npm install eslint --save-dev
  • npm install --save-dev --save-exact prettier
  • npm install sass

ソースコード

今回作成したコードは下記になります。

App.tsx

import React, { useState, useEffect } from "react";
import "./App.css";
import axios from "axios";
import Highcharts from "highcharts";
import HighchartsReact from "highcharts-react-official";
import "./App.scss";

// SPEC: 各APIデータの型
type PrefecturesData = {
  prefCode: number;
  prefName: string;
};

type PopulationData = {
  year: number;
  value: string;
};

export default function App() {
  // ステートの定義
  const [prefectures, setPrefectures] = useState<PrefecturesData[]>([]);
  const [populationData, setPopulationData] = useState<PopulationData[]>([]);
  const [selectedPrefectures, setSelectedPrefectures] = useState<number[]>([]);

  // 47都道府県を配列に格納
  const allPrefectures = []
  prefectures.map((prefecture) => {
    allPrefectures.push(prefecture.prefName)
  })
  const newAllPrefectures = allPrefectures.filter((el, index) => allPrefectures.indexOf(el) === index)

  // 都道府県一覧を取得
  useEffect(() => {
    axios
      .get("https://opendata.resas-portal.go.jp/api/v1/prefectures", {
        // TODO: APIキーをenvファイルに格納してセキュリティ対策をする
        headers: { "X-API-KEY": "取得したAPIキー" },
      })
      .then((res) => {
        setPrefectures(res.data.result);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

  // 人口構成データの取得
  useEffect(() => {
    // TODO: 複数の都道府県が正しく表示されるように修正する
    const addAreas = selectedPrefectures.join(",");
    axios
      .get(
        `https://opendata.resas-portal.go.jp/api/v1/population/composition/perYear?cityCode=-&prefCode=${addAreas}`,
        {
          // TODO: APIキーをenvファイルに格納してセキュリティ対策をする
          headers: { "X-API-KEY": "取得したAPIキー" },
        }
      )
      .then((res) => {
        setPopulationData(res.data.result.data[0].data);
      })
      .catch((err) => {
        console.log(err);
      });
  }, [selectedPrefectures]);

  // チェックボタンの操作
  const handleCheckbox = (prefCode: number) => {
    // SPEC: チェックされた都道府県のcodeをselectedPrefecturesに入れる
    //       チェックが外された都道府県のcodeをselectedPrefecturesから外す
    const isChecked = !selectedPrefectures.includes(prefCode);
    if (isChecked) {
      setSelectedPrefectures((prevState) => [...prevState, prefCode]);
    } else {
      setSelectedPrefectures((prevState) =>
        prevState.filter((code) => code !== prefCode)
      );
    }
  };
  const chartOptions: Highcharts.Options = {
    title: {
      text: "各都道府県の人口増減率",
    },
    yAxis: {
      title: {
        text: "人口構成比(%)",
      },
    },
    plotOptions: {
      series: {
        label: {
          connectorAllowed: false,
        },
        pointInterval: 5,
        pointStart: 1960,
      },
    },
    series: [
      //TODO: 47都道府県分mapでループ処理する.populationDataを使用する。
      {
        name: `${newAllPrefectures[selectedPrefectures[0]-1]}`,
        data: populationData.map(item => item.value),
        type: "line",
      },
    ],
  };
  return (
    <>
      <header className="header">
        <h1 className="header__title">都道府県別の総人口推移グラフ</h1>
      </header>
      <div className="wrapper">
        <h2>都道府県</h2>
        <div className="prefecture__container">
          {prefectures.map((prefecture) => (
            <div key={prefecture.prefCode} className="prefecture__item">
              <input
                className="prefecture__input"
                type="checkbox"
                id={`checkbox-${prefecture.prefCode}`}
                name={prefecture.prefName}
                onChange={() => handleCheckbox(prefecture.prefCode)}
              />
              <label className="prefecture__label">{prefecture.prefName}</label>
            </div>
          ))}
        </div>
        <h2>人口数</h2>
        <HighchartsReact highcharts={Highcharts} options={chartOptions} />
      </div>
    </>
  );
}

App.scss

.header {
  width: 100%;
  background-color: #f5f5f5;
  padding: 10px;

  &__title {
    margin: 0 auto;
    text-align: center;

  }
}

.wrapper {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.prefecture {
  &__container {
    display: flex;
    flex-wrap: wrap;
    text-align: center;
  }

  &__item {
    display: flex;
    padding: 8px;
  }

  &__input {
    margin-right: 8px;
  }
}

API情報の取得と都道府県一覧の表示

まずは、今回使用する「RESAS API」のAPI使用を把握します。

APIエンドポイントがhttps://opendata.resas-portal.go.jpのため

https://opendata.resas-portal.go.jp ←ここに繋げてURLを指定したら欲しい情報が取れそうです。

試しに都道府県一覧情報を取ってきましょう。

RESAS APIを使用するためにはAPIキーを取得する必要があります。

こちらで利用登録することでキーを取得できます。

これをaxiosのgetで呼び出す時にHeadersに指定する必要があります。

キーが登録できたら例に倣って「https://opendata.resas-portal.go.jp/api/v1/prefectures」を叩いてみます。

App.tsxの33~45行目に注目します。

.get(’URL’)のURL部分にhttps://opendata.resas-portal.go.jp/api/v1/prefectures を入れます。

headersには取得したAPIキーを入れます。

この状態で39行目を以下に書き換えます。

.then((res) => {
  console.log(res)
})

yarn start でローカル環境を立ち上げた後、検証ツールを開いてconsole.log()を確認します。

上記のようなデータが確認できたら正しくデータ取得ができてます。

このときconsole.log(res)を取得したデータ構造に対応した指定にしたら、欲しい情報だけ取り出せます。

consol.log(res.data)→data内のmessageとresult情報を取得

consol.log(res.data.result)→47都道府県の情報のみ取得

consol.log(res.data.result[0])→resultの1つ目のデータにある北海道の情報を取得

resというのが引数で、指定したURLまでの情報を指します。ここからさらに情報を絞る場合は、「.」に続けて階層を深く指定していきます。

これで都道府県の情報を取得してあらかじめ用意していたprefecturesというuseStateにデータを格納できました。

次に取得した都道府県一覧を画面に表示させます。

114~125行目に注目します。

<div className="prefecture__container">
  {prefectures.map((prefecture) => (
    <div key={prefecture.prefCode} className="prefecture__item">
      <input
        className="prefecture__input"
        type="checkbox"
        id={`checkbox-${prefecture.prefCode}`}
        name={prefecture.prefName}
        onChange={() => handleCheckbox(prefecture.prefCode)}
      />
      <label className="prefecture__label">{prefecture.prefName}</label>
    </div>
  ))}
</div>

先ほど取得したprefectureをmapで順に表示させています。

mapを使用するときは必ずkeyでid指定を中でする必要があります。key={prefecrure.prefCode}がその役割を果たしています。

prefectureにはprefCodeとprefNameの2つのプロパティが入っているのでそれぞれkeyとlabelで使用します。これで都道府県一覧を画面に表示できました。

inputのラジオボタンは後ほど使うので一旦今はスルーして大丈夫です。

サンプルデータを入れてグラフの表示

次にグラフ表示をさせていきます。今回はHighchartsというライブラリを使用します。

こちらのデモを参考に作成していきます。

VIEW OPTIONSに使用できるデータ構造があります。

これを参考にVSCodeのApp.tsxの80~106行目に注目します。

const chartOptions: Highcharts.Options = {
  title: {
    text: "各都道府県の人口増減率",
  },
  yAxis: {
    title: {
      text: "人口構成比(%)",
    },
  },
  plotOptions: {
    series: {
      label: {
        connectorAllowed: false,
      },
      pointInterval: 5,
      pointStart: 1960,
    },
  },
  series: [
    //TODO: 47都道府県分mapでループ処理する.populationDataを使用する。
    {
      name: `${newAllPrefectures[selectedPrefectures[0]-1]}`,
      data: populationData.map(item => item.value),
      type: "line",
    },
  ],
};

xAxisとyAxisでX軸・Y軸それぞれの名前を指定しています。

series内に実際に描画するデータを入れます。

まずはグラフ表示させるために直でデータを入力してみます。

{
  name: "北海道",
  data: [
    5039206, 5184287, 5338206, 5575989, 5679439, 5643647, 5692321,
    5692321, 5627737, 5506419, 5381733, 5224614, 5016554, 4791592,
    4546357, 4280427, 4004973,
  ],
  type: "line",
},

上記は北海道の人口推移を5年ごとに表したデータです。この形式のデータ格納ができたらグラフ表示を確認できたかと思います。

クリックとグラフ表示を連動させる

次に都道府県横に設置したチェックボックスのon/ offをグラフと連動させていきます。

  • input要素にon,offの状態を検知させる処理を追加

67~79行目に注目します。

※本当はチェックボックスが選ばれてるデータを全てグラフ表示させるつもりで実装しましたが現状だとチェックボックスに対応するグラフ表示は1つだけの実装になってるのをご了承願います。

// チェックボタンの操作
const handleCheckbox = (prefCode: number) => {
  // SPEC: チェックされた都道府県のcodeをselectedPrefecturesに入れる
  //       チェックが外された都道府県のcodeをselectedPrefecturesから外す
  const isChecked = !selectedPrefectures.includes(prefCode);
  if (isChecked) {
    setSelectedPrefectures((prevState) => [...prevState, prefCode]);
  } else {
    setSelectedPrefectures((prevState) =>
      prevState.filter((code) => code !== prefCode)
    );
  }
};

チェックボックスがあるときは用意していた配列にそれに対応するprefCodeが格納されます。

チェックボックスがないときはそのprefCodeが配列から削除されます。

用意した配列のprefCodeに対応する都道府県のデータをseriesのdata内に格納することでグラフ表示をさせています。

スタイル調整

最後にスタイル調整をして終わります。

実装ポイント

  • 日本語でどの流れで実装するか説明できるようにする
  • ロジックは最小単位まで細かく切り分けて説明できるように
  • 悩んだら時間を空けて再挑戦
  • 最低限のレスポンシブ対応できてるかどうかの確認

最初は日本語で実装手順を説明できる必要があると思います。それがわからないと実装することができないため手間がかかるかもですが、日本語で実装手順を細かく説明したチェックリストを用意するのをおすすめします。

実装途中でわからなくなったら、休憩を適宜挟んで再度取り組むと意外と前に進むことが多いなと感じました。

今後の予定

今後はグラフを複数表示できるようにやってみたいと思います。

まだまだスキル不足のため引き続き学習して適宜アウトプットすることで過去の自分に向けてわかりやすく説明できるようにしてみます。(その方が自分のためにもなるし、今学習した方のためになるかと思ったため。)

参考にした本・教材

  • この記事を書いた人
  • 最新記事

てん

都内フロントエンドエンジニア【経歴】新潟大学 ▶︎ web広告代理店マーケ / 営業 ▶︎ 独立 ▶︎ Uber ▶︎エンジニア ■ ブログ・プログラミング・YouTubeが好き ■ 福岡出身27歳 / 夢は起業家

-プログラミング