2020年にWebフロントエンドを勉強する人が作るべきたったひとつのアプリ

最近ではReactやVueを使った**リッチでインターラクティブなUI**がどんどん主流になってきていますし、2020年以降もこの流れは加速し続けるでしょう。

**SPA**（Single Page Application）や**PWA**（Progressive Web Application）の普及によって今までモバイルでしかできなかったことがwebでもどんどんできるようになってきています。

また、**Firebase**を使うことでクラアントサイドだけの高速なサービス開発が可能になってきていて、今後ますます**Webフロントエンドのニーズは増える**のは確実です。

（サーバーサイドが必要ないという主張がしたいのではありませんが）

# Webフロントエンドをどのように勉強するのか

## 初心者に立ちはだかる壁

しかし、何か作ってみようと思ってもなかなかほどよいアプリがありません。TODOぐらい簡単なものだと雰囲気を掴むのにはちょうどいいですが、**TODO程度のアプリケーションでは実務レベルに通用する知識は身につきません。**

面接に「TODOアプリを作りました！」と持っていっても、「それだけ？」と突き返されてしまうでしょう。

逆に、大規模なものを作ろうとすると**工数がかかりすぎてすぐに挫折**してしまいます。Webフロントは思ってるより工数がかかることが往々にしてあります。

設計がしっかりとしていないとバグまみれになってしまうので、いきなり大きすぎるアプリケーションに挑戦するのはおすすめできません。

残念ながらrailsチュートリアルのように、体系的にWebフロントを学べる無料の教材もないのです。

progateで学べることもせいぜい基礎の基礎ぐらいです。

## Googleカレンダーというソリューション

では、いい勉強方法はないのか。そんなことはもちろんありません。

**レベルアップを積めつつ挫折しない程度**のアプリがあります。それが**Googleカレンダー**です。

この記事では**なぜGoogleカレンダーがちょうど勉強にいいレベルなのか**を紹介していきます。

以下のようなアプリを作成しました。

![overview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211808/47c04c7b-e1f9-0227-84c9-5e633a44cb8b.gif)

[デモサイト](https://front.dragon-taro.now.sh/)

実装にはReact/Reduxを用いていますが、各々の勉強してみたい言語に置き換えて読んでください。

Googleカレンダーを一人で作れるようになったのであれば、**脱Webフロント初心者**と胸を張って言えるでしょう！

※ デモサイトではデータの永続化はしていません

# なぜGoogleカレンダーなのか

## ほどよいコンポーネント量（7つ）

```tree
├── AddScheduleDialog
│   ├── container.jsx
│   ├── presentation.jsx
│   └── style.css
├── CalendarBoard
│   ├── container.jsx
│   ├── presentation.jsx
│   └── style.css
├── CalendarElement
│   ├── index.jsx
│   └── style.css
├── CurrentScheduleDialog
│   ├── container.jsx
│   ├── presentation.jsx
│   └── style.css
├── ErrorSnackBar
│   ├── container.jsx
│   └── presentation.jsx
├── Navigation
│   ├── container.jsx
│   └── presentation.jsx
└── Schedule
    ├── index.jsx
    └── style.css
```

僕が実際に作ってみたときはコンポーネントは7つでした。

<img width="782" alt="スクリーンショット 2020-01-26 15.50.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211808/5c1bc855-7a26-10c0-f19b-ee23b855843b.png">

このような構成でコンポーネントを作成しました。残り3つはdialogなどなのでこのコンポーネントツリーとは別に構築して、reduxがある状態になったときにrenderされるようにしました。

流石に一個のファイルで済ますには大きすぎますし、適当に分けすぎるとギリギリ何かを実装しようとしたときにめちゃくちゃ面倒なバグが発生しうるぐらいのサイズ感なのです。

それほどコンポーネントの量が多くないのでレイヤー分けはしていません。

しかし、もしMaterial Design系のライブラリを使わなかった場合はかなりのUIパーツが必要になるので、Atomic Designなどのレイヤー分けが必要になると思います。かなり大変にはなるとは思いますが、それはそれでとてもいい設計の練習になるでしょう。

## 程よいreduxの状態の量（4つ）

```tree
.
├── addSchedule
│   ├── actions.js
│   └── reducer.js
├── calendar
│   ├── actions.js
│   └── reducer.js
├── currentSchedule
│   ├── actions.js
│   └── reducer.js
├── rootReducer.js
└── schedules
    ├── actions.js
    ├── effects.js
    └── reducer.js
```

自分でreduxのアプリを作ってみるとなかなか3個以上にはならず、複雑な状態管理でないのでreduxの恩恵を理解できません。

しかし、4つぐらいになってくると、コンポーネントで管理するにはかなりつらいのでreduxで作る意味理解できるようになってきます。どう分割してどう組み合わせるかを考える必要があるという意味でカレンダーはかなりおすすめです。

たとえば、予定は日付と一緒に管理するかどうか、カレンダーは日付の配列をreduxのstateにするのかそれとも年月だけを持っておくのか、、、などかなりたくさんのことを考える必要がありました。

## クライアント側のロジックが多く工夫する必要がある

いざWebフロントのアプリを作ろうと思っても、気づいたらほとんど**情報を表示できるだけ**のアプリになっています。フォームが１つだけでその値によって表示が変わるぐらいのアプリになってしまいがちです。

たくさんのフォームを作成すれば複雑にできますが、Webフロントの勉強のためにかなり大掛かりなサーバーを用意する必要があり現実的ではありません。

それにインタラクティブさの不要なフォームが個人開発レベルではほとんどでしょう。そのようなフォームであればHTMLだけで実装できるのでReactを使う意味がありません。

しかし、Googleカレンダーを作るとなると話は変わってきます。

サーバー側の実装は最低限（予定を管理するCRUDのAPIサーバーのみ）で十分ですし、データを永続化をしないクライアントだけの実装でもかなり複雑になります。

というのも、**カレンダーそのものを一から作る**必要があるのと、**カレンダーの配列とその月の配列をうまく合わせて表示**させる必要があるからです。そしてこれらをうまくやってくれてかつMaterial Designに準拠したライブラリはないのです。

共通のロジックを分離したりロジックをどこに書くかという設計を検討する必要がありかなりいい訓練になります。僕は、`service`というディレクトリを作ってそこにロジックを記述するようにしました。

## UIライブラリの使い方を勉強できる

「UIライブラリを使うのは甘えだ！」という考えの方もいらっしゃるかもしれません。

しかし、**既存のライブラリを使って爆速で一定以上のクオリティのものを作る**という訓練が積めるのでむしろ使った方が成長が見込めます。

[MaterialUI](https://material-ui.com)はドキュメントもしっかり揃っているのでドキュメントを読む練習にもなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211808/b9560243-94a1-6d00-f958-a30ad452dd8b.png)


「UIライブラリの」と書きましたが、**ライブラリ全般の使い方を学ぶことができる**のはかなりのメリットです。

## 日付の扱いをマスターできる

カレンダーを作成する上で日付ライブラリはマストです。大抵のアプリケーションだと、日付のフォーマットぐらいしか使うことがありませんが、カレンダーを作るとなるとそうはいきません。

ライブラリの提供している機能をフル活用してカレンダーのロジックを作る必要があります。

```js
const createCalendar = month => {
  const firstDay = getMonth(month);
  const firstDayIndex = firstDay.day();

  return Array(35)
    .fill(0)
    .map((_, i) => {
      const diffFromFirstDay = i - firstDayIndex;
      const day = firstDay.add(diffFromFirstDay, "day");

      return day;
    });
};
```

例えば、上記のコードは日付の配列を作成するためのものです。カレンダーは前後の月を表示する必要になってくるので、日付の演算をしてカレンダーを生成するのがもっとも楽です。うまく配列を操って目的の出力を得る必要があるので、アルゴリズム的にも考えて実装する必要があります。

僕も実際にカレンダーを作ってみて初めて日付の演算などを使いとてもいい勉強になりました。

## APIの実装を盛り込みやすい

クライアントだけで完結させることもできますが、せっかくならサーバー側も実装して非同期処理を盛り込んだ方がより現場に近いプロダクトに仕上げることができます。

先ほども述べたように、API側は予定の管理ぐらいしかやることがないので実装がとても楽です。

最低限のAPIを実装したリポジトリを用意したので、よかったら使ってください！[APIの仕様書](https://github.com/Dragon-taro/calender-app/tree/master/server)も書いてあります。

https://github.com/Dragon-taro/calender-app

dbの接続が切れた時のリトライが実装できていないのでPRお待ちしております。。w

## 追加できる機能がたくさんある

TODOアプリやブログアプリだと思いつくことが限られていますが、Googleカレンダーなら無限に作り込み要素があります。

そして本家からアイデアをもらえばいいだけなので何を実装したらいいかやUIを考えるコストがかかりません。

追加できそうな機能を以下にあげてみます。

- 予定の編集
- ログイン・認証
- 予定の共有
- 表示の変更（月・週・日）

これを全部実装できるようになっている頃にはきっと現場の第一線で活躍できているでしょう。

※ 一部、利用規約に反していたため内容を変更しました。不快な思いをさせてしまったことお詫び申し上げます。