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

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分

useReducer

useReducer

起きたことを渡す

前のレッスンでは、押したその場で「次の状態」を計算していました。useReducer はここを2つに分けます。部品は起きたことだけを伝え、次の状態を決める仕事は1つの関数にまとめます。

その関数を reducer と呼びます。形は決まっています。

TypeScript (JSX)

function qtyReducer(qty: number, action: QtyAction): number { // いまの状態と、起きたこと。返すのは次の状態 }

第1引数がいまの状態、第2引数が起きたこと、戻り値が次の状態です。それ以外のことはしません。通信もしないし、画面も触りません。同じものを渡せば必ず同じものが返る、ただの計算です。

switch で遷移を並べる

fleama のカートに入っているスニーカーの数量を、この形で書いてみます。

TypeScript (JSX)

type QtyAction = "increase" | "decrease" | "reset"; function qtyReducer(qty: number, action: QtyAction): number { switch (action) { case "increase": return qty + 1; case "decrease": return qty > 1 ? qty - 1 : 1; case "reset": return 1; default: return qty; } }

数量の決まりが1か所に並びました。1未満に減らさない、という規則もここにしかありません。あとから「上限は10まで」を足すときも、直すのはこの関数だけです。

useReducer で繋ぐ

部品側はこう書きます。

TypeScript (JSX)

const [qty, dispatch] = useReducer(qtyReducer, 1);

第1引数が reducer、第2引数が初期値です。返ってくるのは、いまの状態と dispatch の組です。useState の [qty, setQty] とよく似た形をしています。

押したときは、次の値ではなく起きたことを送ります。

TypeScript (JSX)

<button onClick={() => dispatch("increase")}>+1</button>

dispatch("increase") を読んだ人は「数量を1つ増やす合図を送った」とだけ分かります。いくつになるのかは reducer を見に行けば必ず書いてある。この分担が useReducer の値打ちです。

演習

カートの数量を reducer で動かします。

ヒント

switch (action) の case は、QtyAction に書いた3つの文字と同じ綴りにします

1より下にしないところは qty > 1 ? qty - 1 : 1 と書けます

ボタンは onClick={() => dispatch("increase")} の形です

App.tsx
プレビュー

できているか

  • 最初の数量が1になっている
  • +1 で数量が2、小計が 9600 円になる
  • もう一度 +1 で数量が3、小計が 14400 円になる
  • -1 で数量が2に戻る
  • 1つに戻すで数量が1に戻り、そこから -1 を押しても1のまま
  • useReducer に reducer を渡している
  • any で逃げていない
エディタを読み込んでいます