はじめに
Reactをつかってたくさんのアプリを作りたいと思い、
今回から「React 100本ノック」を始めることにしました。
小さなアプリを100個作る
ことで、Reactの基本から実践的な開発まで段階的に振り返っていくことを目標としています。また、作ったものはすべてGitHubに残していきます。
最終的には、
- React
- TypeScript
- API
- データベース
- Docker
- CI/CD
- AWS
なども取り入れながら、徐々に要素を増やしていきます。
React 100本ノックの目的
今回の100本ノックでは、単純に「100個作る」ことだけを目的にはしません。
それぞれのアプリで、
「今回は何を理解するのか?」
を決めて、実際に手を動かしながら進めていきます。
最初はReactの基本から始めて、徐々に開発環境やインフラまで広げていく予定です。
React基礎
↓
React応用
↓
API
↓
データベース
↓
Docker
↓
テスト
↓
GitHub Actions / CI/CD
↓
AWS
↓
総合アプリ
第1回:学習記録アプリ
1本目は、「学習記録アプリ」 を作りました。
学習内容と学習時間を入力すると、学習履歴として表示され、
登録した学習時間の合計も表示されるシンプルなアプリです。
作ったもの
今回はデータベースなどは使用せず、
ブラウザ上でデータを管理しています。
使用技術
今回使用した技術は以下です。
- React
- TypeScript
- Vite
今回はReactの基本を理解することを優先したため、
- Docker
- DB
- API
- GitHub Actions
- AWS
などは使用していません。
これらは今後の課題で段階的に導入していきます。
ローカル環境構築
Viteを使ってReact + TypeScriptのプロジェクトを作成しました。
npm create vite@latest react-001-study-record -- --template react-ts
作成したプロジェクトに移動します。
cd react-001-study-record
必要なパッケージをインストールします。
npm install
開発サーバーを起動します。
npm run dev
起動すると、
http://localhost:5173/
でアプリを確認できます。
今回実装したこと
1. 学習記録をstateで管理
まず、学習記録のデータの形をTypeScriptで定義しました。
type StudyRecord = {
id: number;
title: string;
hours: number;
};
例えば、
{
id: 1,
title: "Reactを勉強する",
hours: 2
}
という形になります。
この学習記録を配列として管理します。
const [records, setRecords] = useState<StudyRecord[]>([]);
2. useStateで入力値を管理
学習内容と学習時間をuseStateで管理しました。
const [title, setTitle] = useState("");
const [hours, setHours] = useState("");
入力欄の値が変更されたら、stateを更新します。
onChange={(event) => setTitle(event.target.value)}
例えば、
ユーザーが「React」と入力
↓
onChange
↓
setTitle("React")
↓
titleが更新
という流れです。
3. 学習記録を登録
登録ボタンを押したときにhandleSubmitを実行します。
<form onSubmit={handleSubmit}>
入力された値から、新しい学習記録を作ります。
const newRecord: StudyRecord = {
id: Date.now(),
title: title,
hours: Number(hours),
};
そして、現在の学習記録に追加します。
setRecords([...records, newRecord]);
ここで、
現在のrecords
+
新しいrecord
↓
新しいrecords
という形でデータが更新されます。
4. mapを使って学習履歴を表示
登録した学習記録は配列に入っています。
そこでmap()を使って1件ずつ画面に表示しました。
records.map((record) => (
<li key={record.id}>
{record.title}:{record.hours}時間
</li>
))
例えば、
records
[
React 2時間
TypeScript 3時間
]
というデータを、
React 2時間
TypeScript 3時間
というHTMLの一覧に変換しています。
5. reduceで合計時間を計算
最後に、登録された学習時間を合計します。
const totalHours = records.reduce(
(total, record) => total + record.hours,
0
);
例えば、
React 2時間
TypeScript 3時間
Git 1時間
なら、
2 + 3 + 1 = 6時間
となります。
Reactのデータの流れ
今回のアプリを作っていて、一番理解したかったのがこの部分です。
ユーザーが入力
↓
onChange
↓
useState
↓
登録ボタンを押す
↓
handleSubmit
↓
新しい学習記録を作成
↓
setRecords
↓
recordsが更新
↓
Reactが再描画
↓
mapで一覧表示
↓
reduceで合計を計算
Reactは単純に「HTMLを書くもの」というより、
状態が変化すると、それに合わせて画面が更新される
という考え方が重要なのだと感じました。
🏐 バレーボールに例えてみる
Reactのデータの流れを理解するために、
バレーボールに例えて考えてみました。
🏐 ボールが来る
↓
レシーブ
↓
トス
↓
アタック
↓
得点
↓
スコアボード更新
Reactにすると、
ユーザー入力
↓
onChange
↓
useState
↓
handleSubmit
↓
setRecords
↓
records
↓
map / reduce
↓
画面表示
というイメージです。
例えばuseStateは、
現在の状態を持っているスコアボードのようなもの。
setRecordsは、
得点が入ったときにスコアボードを更新する処理。
map()は、
選手を1人ずつ確認して一覧にするような処理。
reduce()は、
得点を合計するような処理。
このように置き換えると、個人的にはかなり理解しやすくなりました。
苦戦したこと
useStateと普通の変数の違い
最初は、
「変数に値を入れるだけなら、普通のJavaScriptの変数でいいのでは?」
と思っていました。
しかしReactでは、画面に表示するデータをstateとして管理することで、
stateが変更されたときにReactが画面を更新してくれます。
今回実際にフォームを作ってみることで、
普通の変数
↓
値を保存する
useState
↓
Reactが管理する状態
↓
変更されると画面に反映される
という違いを少し理解できました。
今回学んだこと
今回特に学んだのは以下です。
-
useStateによるstate管理 -
onChangeによる入力値の取得 -
onSubmitによるフォーム送信 -
map()による一覧表示 -
reduce()によるデータ集計 - TypeScriptによる型定義
- Reactにおけるデータの流れ
特に、
ユーザー操作
↓
state変更
↓
Reactが再描画
↓
画面が変わる
というReactの基本的な流れを、実際に手を動かして確認できました。
GitHub
今回作成したリポジトリはこちらです。
https://github.com/spring46-stack/react-001-study-record
今後について
今回はReactの基本だけに絞りました。
今後は少しずつ難易度を上げていきます。
React基礎
↓
React応用
↓
CRUD
↓
API
↓
DB
↓
TypeScript
↓
Docker
↓
テスト
↓
GitHub Actions
↓
CI/CD
↓
AWS
↓
総合アプリ
100本目では、これまで学んだ技術を組み合わせて、
実践的なアプリケーションを作ることを目標にします。
まとめ
React 100本ノックの1本目として、
学習記録アプリを作成しました。
今回は、
useStateonChangeonSubmitmapreduce
を中心に、Reactの基本的なデータの流れを学びました。
まだまだ小さなアプリですが、
「実際に作って、分からないところを調べて、理解する」
ことを大切にして、これから100本続けていきます。
次回も今回より少しだけ難しいアプリを作り、
Reactの理解を深めていきます。
