コース一覧
React状態管理:カスタムフック・Context・Reducer
Actionのunion型

React状態管理:カスタムフック・Context・Reducer

カスタムフック、フックのルール、Context、useContext、useReducer、Actionのunion型を扱う全21レッスンの状態管理コースです。fleamaの商品・フォーム・テーマ・ユーザー・カート状態を、再利用可能なロジックと予測可能な状態遷移へ整理します。

1
カスタムフック
01. なぜカスタムフックか10分
02. useItemsを作る15分
03. useFormを作る15分
04. フックのルール15分
05. フックに型を付ける15分
06. つくる - フック化完了20分
07. 第4章クイズ15分
2
useContext
01. バケツリレーの限界15分
02. Contextを作る15分
03. useContextで使う15分
04. テーマの全体共有15分
05. ユーザー情報の共有15分
06. つくる - Context整備20分
07. 第5章クイズ15分
3
useReducer
01. setStateの散らかり15分
02. useReducer15分
03. Actionのunion型15分
04. カートreducer15分
05. 使い分け10分
06. つくる - カート完成20分
07. 第6章クイズ15分

Actionのunion型

Actionのunion型

action は「起きたこと」の書類

前のレッスンの action は "increase" という文字だけでした。カートではそうはいきません。「どの商品を入れるのか」「どの行を外すのか」「いくつに変えるのか」という中身が要ります。

そこで action をオブジェクトにします。何が起きたかを type に書き、必要な材料を一緒に載せます。

TypeScript (JSX)

dispatch({ type: "ADD", item }); dispatch({ type: "REMOVE", id: "1" }); dispatch({ type: "CHANGE_QTY", id: "1", qty: 3 });

操作の一覧をユニオン型で書く

3つの action は、載せている材料がそれぞれ違います。ADD には商品そのものが要りますが、REMOVE に要るのは id だけです。これを1つの型で表すのがユニオン型です。TypeScript入門でやった「どれか1つ」の型が、ここで効いてきます。

TypeScript (JSX)

type CartAction = | { type: "ADD"; item: Item } | { type: "REMOVE"; id: string } | { type: "CHANGE_QTY"; id: string; qty: number };

読み方は「CartAction はこの3つのどれか」です。この型が付いていれば、dispatch({ type: "REMOVE" }) のように id を忘れた呼び出しは、その場で怒られます。カートにできることの一覧が、型として1か所に書いてある状態になりました。

switch を書くと絞り込まれる

いいことがもう1つあります。reducer の中で action.type を switch にかけると、TypeScript は case ごとに「これはこの形の action だ」と絞り込みます。

TypeScript (JSX)

case "ADD": return [...cart, { item: action.item, qty: 1 }]; case "REMOVE": return cart.filter((line) => line.item.id !== action.id);

ADD の中では action.item が読めて、action.id は無いと言われます。REMOVE の中では逆です。これを絞り込みと呼びます。書ける場所でしか書けないので、材料の取り違えが起きません。

type に string を使うと、この絞り込みは働きません。どの case でも中身が分からないままになり、型を書いた意味がほとんど消えます。

演習

CartAction を3つのユニオン型にして、削除と数量変更の dispatch を書きます。

ヒント

ユニオン型は縦棒で並べます。行頭の | は1つめに付けても構いません

削除は dispatch({ type: "REMOVE", id: line.item.id }) です

+1 は数量そのものを送ります。dispatch({ type: "CHANGE_QTY", id: line.item.id, qty: line.qty + 1 }) の形です

App.tsx
プレビュー

できているか

  • スニーカーを入れると合計が 4800 円になる
  • 革靴も入れると2行になり合計が 14600 円になる
  • スニーカーの +1 で数量が2、合計が 19400 円になる
  • スニーカーを削除すると革靴だけが残る
  • REMOVE を型に書いている
  • CHANGE_QTY を型に書いている
  • any で逃げていない
エディタを読み込んでいます