1. ホーム
  2. 記事一覧
  3. 初心者向け!React × TypeScriptで作る天気予報アプリハンズオン

2025.01.08

初心者向け!React × TypeScriptで作る天気予報アプリハンズオン

    はじめに

    ReactやTypeScriptを使ったフロントエンド開発に挑戦している皆さん、次のステップに進む準備はできていますか?「Todoリスト以外のアプリを作ってみたいけれど、次のアイデアが浮かばない」「APIやRESTの仕組みは何となく知っているけれど、実際に使うのは難しそう」と感じている方もいるかもしれません。

    この記事では、ReactとTypeScriptを使って、天気予報アプリを一緒に作りながら、API通信やRESTの基本を学びます。さらに、TypeScriptを活用して型定義を行い、安全で効率的なコードを書く方法もわかりやすく解説します。「APIって何?」「REST APIってどう使うの?」といった疑問を解消しながら、実践を通じて自分のスキルを一歩前進させてみませんか?

    「次のステップに進む」ためのハンズオン、一緒にはじめていきましょう。

    この記事について

    学べること

    • APIやRESTの基本概念を理解
    • React × TypeScriptを使用したフロントエンドアプリケーションの開発
    • TypeScriptを使った型定義
    • Axiosを使用したAPIからのデータ取得方法

    対象者

    • フロントエンド初心者
    • React × TypeScriptでの型定義について理解を深めたい方

    APIとRESTとは何か

    APIやRESTは、フロントエンドエンジニアにとって重要な概念です。アプリケーションが他のソフトウェアとどのように通信しているのか理解することで、データのやり取りがクリアになります。APIに関する疑問を一つずつ解消し、天気予報アプリの開発を進める準備を整えましょう。

    APIとは何か?その仕組みと役割を理解

    APIは(Application Programming Interface)の略で、アプリケーション同士がデータや機能をやり取りするための「橋渡し」のような存在です。APIは異なるソフトウェア同士を繋ぎ、情報交換の仕組みを提供します。情報交換にはルール(プロトコルや仕様)が定められており、ソフトウェアはそのルールに従って情報のやり取りを行います。

    たとえば、天気予報アプリを作る場合、気象情報は自分で計算するのではなく、外部の気象データ提供サービス(API)を使って取得します。APIを利用することで、他のシステムやサービスが提供するデータや機能を簡単に使えるようになるのです。

    RESTとは何か

    「REST」とは「Representational State Transfer」の略で、APIの設計スタイルの一つです。以下のような原則に基づいて設計されたAPIを指します。

    • リソース志向

      天気情報で例えると、天気の地点、天気の状況などといったデータを「リソース」として扱います。その各リソースへは、URL(エンドポイント)を指定してアクセスします。

      エンドポイントへのアクセス例

      https://api-example.weather.com/city/tokyo
    • HTTPメソッドを活用

      REST APIでは、HTTPメソッドを使ってリソースに対する操作を指定します。APIを利用するためにはHTTPメソッドの知識が必要になるため、ここで簡単に紹介します。

      メソッド内容
      GETサーバーから必要な情報を取得
      POST新しいデータをサーバーに送信
      PUT指定したサーバー上の既存情報を、新しい情報に変更
      PATCH変更がある部分だけをサーバー送信して情報を更新
      DELETE指定したサーバーの情報を削除
    • ステートレス(無状態性)

      ステートレスとは各リクエストが独立していることを意味し、リクエストごとに必要な情報を全て含める必要があります。これにより、サーバー側は一つ一つのリクエストに関連する状態を保持する必要がなくなります。

    RESTful APIとは?REST APIと何が違うの?

    RESTful APIとは、RESTの原則により厳密に従って作られたAPIのことを指します。「ful」という接尾辞には「〜に満ちた」という意味があり、「RESTful」は「RESTの原則に満ちた」という意味合いになります。

    REST APIとRESTful APIは、大まかに言えば同じようなものと考えて問題ありません。どちらもRESTの原則に基づいていますが、RESTful APIの方がより厳格にその原則を守っている、という違いです。

    2つの違いを深堀するとかえって理解を難しくしてしまうため、この記事では触れません。違いを深掘りするよりも、RESTの基本原則に注目してAPI設計や利用の考え方を学ぶことが、より実践的で役立つと考えています。

    次のセクションでのハンズオンでアプリケーションを作りながら、「リソース指向のURL設計やHTTPメソッドの使い方」といったRESTの原則に従ったAPI通信の理解を深めていきましょう。

    関連記事

    APIやリクエストメソッドなど、フロントエンドでのAPIとのやりとりについて、以下の記事でも解説しています。あわせて参照にしてみてください。

    JavaScriptの基本、Fetch APIを理解しよう

    https://envader.plus/article/465

    REST APIとは?特徴やメリットをわかりやすく解説

    https://envader.plus/article/83

    WEB開発の基礎 フロントエンドとバックエンドの連携とAPIの役割

    https://envader.plus/article/210

    React × TypeScriptで作る天気予報アプリ

    ReactとTypeScriptを使用したプロジェクトを始めるには、いくつかのツールや環境が必要です。初めての方でもわかりやすい手順で、開発環境をセットアップしていきます。このハンズオンでは、Node.jsやVite、天気予報APIの取得方法までをカバーしていますので、一つずつ一緒に準備を進めましょう。

    必要な環境とツール

    • コードエディター(この記事ではVSCodeを使用)
    • Node.jsとnpm
    • React、TypeScript、Vite、Axios
    • 天気予報 API(livedoor 天気互換)

    使用技術について

    このハンズオンでは、React、TypeScript、Axiosを使用します。それぞれの基本については簡単に触れる程度となりますので、詳しく知りたい方は以下の記事を参考にしてみてください。

    フロントエンジニアを目指す初心者向け TypeScriptの基礎を解説

    https://envader.plus/article/340

    初心者向け!TypeScript型入門

    https://envader.plus/article/515

    JavaScriptのライブラリ、Axiosを理解しよう

    https://envader.plus/article/478

    使用する天気予報APIについて

    天気予報APIは「天気予報 API(livedoor 天気互換)」を使用します。通常、APIを使用する際はアカウント登録やAPIキー取得などが必要ですが、「天気予報 API(livedoor 天気互換)」では諸手続きが不要で簡単に天気情報を取得できます。サービスの詳細については以下のサイトをご覧ください。

    天気予報 API(livedoor 天気互換)

    https://weather.tsukumijima.net/

    アプリケーションの開発準備

    Reactプロジェクトをセットアップし、必要なライブラリやツールをインストールしていきます。一つずつ順を追って進めていきましょう。

    プロジェクトのセットアップ

    • 新しいReactプロジェクトの作成
    • Axoisのインストール

    はじめに、Node.jsがPCにインストールされているか確認します。以下のようにバージョンが表示されれば、PCにnode.jsがインストールされています。

    node -v
    v20.18.1

    表示されない場合は以下のサイトからインストールします。初心者の方はLTS(長期サポートを保証されたバージョン)のインストールをお勧めします。

    Node.js

    https://nodejs.org/en

    PCの任意のディレクトリ内でViteを使用しプロジェクトを作成します。以下のコマンドを実行します。

    npm create vite@latest

    Viteについては公式サイトをご覧ください。

    Vite

    https://ja.vite.dev/

    コマンドを実行後、以下の選択肢が表示されますので、それぞれの項目を1つずつ選びます。

    • Project name:weather-app
    • Select a framework:React
    • Select a variant:TypeScript + SWC
    ✔ Project name: … weather-app
    Select a framework: › React
    ? Select a variant: › - Use arrow-keys. Return to submit.
        TypeScript
    ❯   TypeScript + SWC
        JavaScript
        JavaScript + SWC
        React Router v7 ↗

    以下が表示されれば、プロジェクト作成完了です。

    done

    次に作成したプロジェクトのディレクトリに移動し、必要な依存関係をインストールします。

     cd weather-app ←ディレクトリの移動
     npm install     ←依存関係のインストール

    完了後、以下を実行してプロジェクトを起動します。

    npm run dev

    ブラウザ上で以下のように表示されれば環境構築が完了です。

    ハンズオンではAxiosを使用して、APIからデータを取得します。以下のコードを実行してAxiosをプロジェクトにインストールします。

    npm install axios

    次にAxiosに必要なTypeScriptの型定義をインストールします。

    npm install @types/axios

    ここまでで、ハンズオンに必要なツールが揃いました。ではいよいよ、コードの編集をしていきましょう。

    天気予報アプリの実装

    天気予報アプリの実装に進みます。API通信の実装、型定義、データの表示方法などを順番に解説しながら、アプリを完成させていきます。初心者の方でもステップごとに進められる内容にしていますので、一緒に取り組んでいきましょう。

    プロジェクトのsrcディレクトリ内に以下のファイルを作成し、各ファイルをそれぞれ編集します。

    • App.tsx

      このメインコンポーネントです。データを取得し、天気情報を表示します。

    • types.ts

      APIから取得するデータの型を定義します。

    • WeatherCard.tsx

      天気情報を画面に表示するためのコンポーネントです。

    • api.tsx

      天気APIからデータを取得します。

    App.tsx

    このファイルでは、天気APIからデータを取得し、画面に天気情報を表示します。

    // App.tsx
    
    import { useState, useEffect } from 'react';
    import WeatherCard from './WeatherCard';
    import { WeatherData } from './types';
    import apiClient from './api';
    
    const App = () => {
        // 天気情報のstate:types.tsで定義した型(WeatherData)を使用して型定義
        const [weather, setWeather] = useState<WeatherData | null>(null);
        // エラーメッセージを管理するstate:string型またはnull型を使用して型定義
        const [error, setError] = useState<string | null>(null);
    
        // コンポーネントが表示されたときに一度だけ実行され、APIから天気データを取得
        useEffect(() => {
            // 天気情報を取得する非同期関数
            const fetchWeather = async () => {
                try {
                    // Axiosを使って天気APIからデータを取得:ジェネリクス<WeatherData>でレスポンスデータの型を指定
                    const response = await apiClient.get<WeatherData>('/forecast/city/130010');
                    setWeather(response.data); // 天気情報をstateにセット
                } catch (err) {
                    // エラーが発生した場合、エラーメッセージをstateにセット
                    setError((err as Error).message);
                }
            };
    
            fetchWeather(); // 天気情報を取得
        }, []);
    
        return (
            <div style={{ textAlign: 'center', marginTop: '20px' }}>
                <h1>天気予報アプリ</h1>
                {error ? (
                    // エラーがある場合はエラーメッセージを表示
                    <p style={{ color: 'red' }}>{error}</p>
                ) : weather ? (
                    // 天気情報が取得できた場合はWeatherCardコンポーネントにデータを渡して表示
                    <WeatherCard
                        city={weather.location.city}
                        weather={weather.forecasts[0].telop}
                        temperature={{
                            max: weather.forecasts[0].temperature.max?.celsius || 'N/A', // 最高気温
                            min: weather.forecasts[0].temperature.min?.celsius || 'N/A', // 最低気温
                        }}
                        iconUrl={weather.forecasts[0].image.url} // 天気アイコンのURL
                    />
                ) : (
                    // データ取得中のローディングメッセージ
                    <p>天気情報を取得中...</p>
                )}
            </div>
        );
    };
    
    export default App;

    このファイルのポイントとなるのは、以下のコードで使用しているジェネリクスです。

    const response = await apiClient.get<WeatherData>('/forecast/city/130010');
    • ジェネリクスを使用した型定義

      getメソッドに<WeatherData>を渡しています。この部分で「APIのレスポンスデータがWeatherData型である」と指定しています。

    • ジェネリクスの型が渡される場所

      <WeatherData>で指定した型は、apiClient.getメソッドの返り値(response)に適用されます。このため、response.dataの型がtypes.tsで定義したWeatherData型として扱われます。これにより、APIレスポンスの型が一貫してWeatherData型として認識されるようになっています。

    ジェネリクスとは?

    ジェネリクスは、「型を引数として渡せる仕組み」です。関数に値を引数として渡すように、ジェネリクスを使うと型も引数として渡せます。これにより、コードを柔軟に記述できます。

    types.ts

    このファイルでは、天気APIから取得したデータの型を定義しています。型をここにまとめておくことで、他のコンポーネントや関数でも繰り返し使えるようになります。

    // types.ts
    
    // 天気情報APIのレスポンスデータ型
    export type WeatherData = {
        location: {
            city: string; // 都市名
        };
        forecasts: {
            telop: string; // 天気の説明
            temperature: {
                max: { celsius: string | null } | null; // 最高気温(nullの場合もある)
                min: { celsius: string | null } | null; // 最低気温(nullの場合もある)
            };
            image: {
                url: string; // 天気アイコンのURL
            };
        }[];
    };

    WeatherData型について

    WeatherData型は、天気APIから取得するデータ全体の構造を表しています。次のようなデータが含まれます。

    • location.city

      都市名(例: "東京")

    • forecasts(天気予報のリスト)

      • telop

        天気の説明(例: "晴れ")

      • temperature.max / temperature.min

        最高気温と最低気温。APIからは気温がない場合にnullが返ることがあるため、nullを許容する型になっています。

      • image.url

        天気アイコンのURL

    このファイルで定義した型をApp.tsxでインポートし、APIレスポンスのデータの型を管理しています。

    WeatherCard.tsx

    天気情報を受け取って画面に表示するためのコンポーネントです。WeatherCardProps型を指定し、WeatherCardが受け取るデータ(props)に型定義をしています。

    // WeatherCard.tsx
    
    // WeatherCardコンポーネントで受け取るpropsの型を定義
    type WeatherCardProps = {
        city: string; // 都市名
        weather: string; // 天気
        temperature: {
            min: string; // 最低気温
            max: string; // 最高気温
        };
        iconUrl: string; // 天気アイコンのURL
    };
    
    // WeatherCardコンポーネント
    const WeatherCard = ({ city, weather, temperature, iconUrl }: WeatherCardProps) => {
        return (
            <div
                style={{
                    border: '1px solid #ccc',  // カードのスタイル
                    borderRadius: '10px',
                    padding: '20px',
                    width: '300px',
                    margin: '0 auto',
                }}
            >
                <h2>{city}</h2> {/* 都市名を表示 */}
                <img
                    src={iconUrl}
                    alt={weather}
                    style={{ width: '100px', height: '100px' }} // アイコン画像のサイズ
                />
                <p>天気:{weather}</p> {/* 天気を表示 */}
                <p>
                    気温:最高 {temperature.max}°C / 最低 {temperature.min}°C 
                </p> {/* 気温を表示 */}
            </div>
        );
    };
    
    export default WeatherCard;

    api.tsx

    Axiosを使用してAPI通信を管理するファイルです。axios.createを使い、ベースURLやタイムアウト設定を共通化しています。これにより、コードの再利用性が高まり、複数のAPIリクエストを効率的に処理できます。

    // api.tsx
    
    import axios from 'axios';
    
    const apiClient = axios.create({
        baseURL: 'https://weather.tsukumijima.net/api', // ベースURL
        timeout: 5000, // タイムアウト設定(ミリ秒)
        headers: {
            'Content-Type': 'application/json',
        },
    });
    
    export default apiClient;

    axios.createとは?

    Axiosインスタンスとは、カスタム設定を持つAxiosの独自インスタンス(オブジェクト)を作成し、そのインスタンスを使って複数のリクエストを実行できる仕組みです。これにより、共通の設定やヘッダーを複数のリクエストに適用することができます。

    完成した天気予報アプリの確認

    ファイルを編集後、以下の様な天気が表示されていれば実装完了です。

    ハンズオン全体の振り返り

    このハンズオンを通じて、TypeScriptとAxiosを使ったAPI通信、型安全なデータ操作、そしてコンポーネント分割によるコードの整理方法を学びました。特に、APIレスポンスの型定義(WeatherData)や、ジェネリクスを利用したデータ取得の利便性や安全性を実感できたのではないでしょうか。

    初めのうちは型定義が難しく感じることもありますが、実際にコードを書きながら試していくことで徐々に慣れていきます。ご自身でさまざまな型定義方法を試し、実践を通じて理解を深めていってください。

    まとめと今後のステップアップ

    この記事では、APIとRESTの基礎からReact × TypeScriptを使った実践的なアプリ開発まで、一通りの流れを学びました。このハンズオンで得た知識をさらに広げ、次のステップも試してみてください。たとえば、以下のような機能を追加することで、アプリをカスタマイズする楽しみが広がるかと思います。

    • 詳細な天気情報の追加

      各地域の天気や、気圧、湿度などの詳細なデータを表示

    • ユーザーインタラクションの強化

      場所検索機能や、日付ごとの天気予報を切り替えられるUIを実装

    これらの機能を追加することで、アプリをさらに使いやすい形にカスタマイズできます。また、新たな機能を考え、実装していくプロセスは楽しく、プログラミングスキルの向上にもつながります。

    楽しみながら学び、継続的に挑戦することが成長への近道です。 このハンズオンを一つのきっかけとして、次のステップに進んでいただければ幸いです。

    参考資料

    以下のリンクは、この記事で説明した手順や概念に関連する参考資料です。より詳しく学びたい方は、ぜひご覧ください。

    サバイバルTypeScript

    https://typescriptbook.jp/

    関連記事

    以下はエンベーダーのAPIの関連記事です。ぜひあわせてご覧ください。

    Fast APIでREST APIを作ってみよう 初心者でも簡単にできる環境構築から解説

    https://envader.plus/article/333

    GraphQLとREST:API技術の選択に悩んでいる方へ

    https://envader.plus/article/87

    【番外編】USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

    IT未経験者必見 USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

    プログラミング塾に半年通えば、一人前になれると思っているあなた。それ、勘違いですよ。「なぜ間違いなの?」「正しい勉強法とは何なの?」ITを学び始める全ての人に知って欲しい。そう思って書きました。是非読んでみてください。

    「フリーランスエンジニア」

    近年やっと世間に浸透した言葉だ。ひと昔まえ、終身雇用は当たり前で、大企業に就職することは一種のステータスだった。しかし、そんな時代も終わり「優秀な人材は転職する」ことが当たり前の時代となる。フリーランスエンジニアに高価値が付く現在、ネットを見ると「未経験でも年収400万以上」などと書いてある。これに釣られて、多くの人がフリーランスになろうとITの世界に入ってきている。私もその中の1人だ。数年前、USBも知らない状態からITの世界に没入し、そこから約2年間、毎日勉学を行なった。他人の何十倍も努力した。そして、企業研修やIT塾で数多くの受講生の指導経験も得た。そこで私は、伸びるエンジニアとそうでないエンジニアをたくさん見てきた。そして、稼げるエンジニア、稼げないエンジニアを見てきた。

    「成功する人とそうでない人の違いは何か?」

    私が出した答えは、「量産型エンジニアか否か」である。今のエンジニア市場には、量産型エンジニアが溢れている!!ここでの量産型エンジニアの定義は以下の通りである。

    比較的簡単に学習可能なWebフレームワーク(WordPress, Rails)やPython等の知識はあるが、ITの基本概念を理解していないため、単調な作業しかこなすことができないエンジニアのこと。

    多くの人がフリーランスエンジニアを目指す時代に中途半端な知識や技術力でこの世界に飛び込むと返って過酷な労働条件で働くことになる。そこで、エンジニアを目指すあなたがどう学習していくべきかを私の経験を交えて書こうと思った。続きはこちらから、、、、

    note記事3000いいね超えの殿堂記事 LINE登録で記事を見る

    エンベーダー編集部

    エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。

    RareTECH 無料体験授業開催中! オンラインにて実施中! Top10%のエンジニアになる秘訣を伝授します! RareTECH講師への質疑応答可

    関連記事