Reactを使ったお天気アプリを作成してみた

## はじめに

Reactを学習していくにあたり、REST APIの勉強を兼ねてお天気アプリを作成してみました。

https://github.com/himorishige/weatherApp

ソースコードのビルドには[OpenWeather API](https://openweathermap.org/)のAPIキーと[Google Maps API](https://developers.google.com/maps?hl=ja)のキーが必要となります。
![Weather App.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268181/4d315685-627d-9c75-c177-db1fd315f45c.png)

## 仕様について

今回、天気アプリ作成にあたり、まず仕様について下記のように項目出しを行いました。  
あらかじめおおざっぱながらも機能を書き出すことで自分が何から手をつけていくのがよいか、また途中で迷子にならないよう進行することができたと思います。  

- ページを表示した時に、WebAPIのgeolocationAPI（位置情報API）を利用して現在地の緯度経度を取得する
- 取得した緯度経度を使ってOpenWeatherAPI経由で天気情報を取得する
- 取得した天気情報を使って現在地付近の情報を表示する
  - 取得日時を表示する
  - 天気アイコンを表示する
  - 現在の気温を表示する
  - 体感温度を表示する
  - 最高気温を表示する
  - 最低気温を表示する
  - 風向きを表示する
  - 風速を表示する
  - 気圧を表示する
  - 湿度を表示する
  - 7日間予報を表示する
  - 1時間ごとの予想気温をグラフで表示する
- 地名から検索ができる

## 利用サービス・利用技術

- [位置情報API](https://developer.mozilla.org/ja/docs/Web/API/Geolocation_API) … 現在地の取得
- [Open Weather API](https://openweathermap.org/) … 天気情報の取得
- [Google Maps API](https://developers.google.com/maps?hl=ja) … 地図情報、住所から経度緯度の取得
- [SNAZZY MAPS](https://snazzymaps.com/) … Googleマップのデザインスタイル
- [Chart.js](https://www.chartjs.org/) … グラフ描画

## 突然のテスト駆動開発へ挑戦

前回ポートフォリオサイトを作ったときにはStorybookへ挑戦したのですが、今回はテストを書いてみるというテーマで開発を開始しました。  
テストについて色々と調べていくと気になったのがテスト駆動開発という言葉。前々から言葉だけは聞いたことがあったのですが、実際にはどういった手法になっているのかまったく知らなかったため和田卓人氏の下記講演の視聴から勉強してみました。

https://www.youtube.com/watch?v=Q-FJ3XmFlT8

さらに上記講演をReactのフロントエンド開発に置き換えた解説記事も参考にしながら、手を動かしていきます。

https://zenn.dev/higa/articles/34439dc279c55dd2ab95

が、すぐに車輪は止まりました笑

自分にはまだ早かったのか、タスクの粒度を細かくしていくことができず複雑怪奇になってしまい、結局部分的なテストコードしか書いていくことができませんでした。。。  
テストを書くということ自体にはとても感銘を受けたので、今後もテストについては勉強を続けながら書いていこうと思います。

## emotionを試す

今回スタイルにつていはemotionのcss Propを使ってみました。

https://emotion.sh/docs/css-prop

Create React App、TypeScript環境で利用するにはひと手間必要で、

ソースの先頭に下記1行を追記する必要があります。

```typescript
/** @jsxImportSource @emotion/react */
```

一例として今回ローディング画面で利用したスケルトンコンポーネントは下記のようになっています。

![recording.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268181/bdcb8b4a-efba-e355-1d68-ea9fcc0b9d4d.gif)

```typescript:/src/components/atoms/Button/index.tsx
/** @jsxImportSource @emotion/react */
import React from 'react';
import { css, keyframes } from '@emotion/react';

export type Props = {
  height?: string;
  width?: string;
  radius?: string;
};

const Skelton: React.VFC<Props> = (props) => {
  const { height = '1.5rem', width = '100%', radius = '0' } = props;

  return (
    <div
      css={skeltonStyle}
      style={{ width: `${width}`, height: `${height}`, borderRadius: `${radius}` }}
    />
  );
};

export default Skelton;

const skeltonAnimation = keyframes`
  0% {
    transform: translateX(-100%)
  }
  100% {
    transform: translateX(100%)
  }
`;

const skeltonStyle = css`
  width: 100%;
  height: 1.5rem;
  line-height: 2;
  background: #d9d9d9;
  position: relative;
  overflow: hidden;
  margin: 0.5rem 0;
  &::before {
    content: '';
    display: block;
    height: 100%;
    width: 100%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
    position: absolute;
    top: 0;
    left: 0;
    z-index: 100;
    animation: ${skeltonAnimation} 1.2s linear infinite;
  }
`;
```

私のVS Code環境だとcss Propを利用すると **css``** を利用したあとのシンタックスハイライトがなんだかおかしくなるので下の方に追いやっています。個人的なイメージとしてはvue.jsの`<style>`ブロックみたいな雰囲気に感じました。

## 苦労した点

位置情報APIの取得、そこからOpenWeatherAPIの取得、Googleマップの表示と非同期処理の完了を待って、また次の非同期処理へという流れが続く部分でかなり混乱してしまいました。  
上記にあわせてuseStateが変数を格納するタイミング、useEffectの実行タイミングの理解も曖昧だったため、さらに悪循環にはまっていきましたが、ひとつずつ`console.log`で動きを確かめながら解消していきました。

## さいごに

今回はテストコードの記載に挑戦しながらアプリを作成してみましたのですが、テストコードを書くことを通じて根本的なロジックというかプログラムの考え方を少しだけ知ることができました。このアプリのテストコードをもう少し書き進めながら、次の制作物でも引き続きテストコードに挑戦していこうと思います。

## 関連記事

https://qiita.com/himorishige/items/3c05786b61a8d4b4c80e

https://qiita.com/himorishige/items/c114fd6fb422a12be5e8

## 参考サイト

位置情報API（geolocation API）

https://developer.mozilla.org/ja/docs/Web/API/Geolocation_API

https://webdrawer.net/javascript/geolocation.html

Google Maps API

https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse#maps_geocoding_reverse-typescript

https://qiita.com/theFirstPenguin/items/dc94aeb1595df1a0aa56

TDD、jest、React Testing Library

https://www.youtube.com/watch?v=Q-FJ3XmFlT8

https://zenn.dev/higa/articles/34439dc279c55dd2ab95

https://zenn.dev/bom_shibuya/articles/5c3ae7745c5e94

https://jestjs.io/ja/

https://testing-library.com/

Chart.js

https://www.chartjs.org/

emotion css prop

https://emotion.sh/docs/css-prop