React状態管理:カスタムフック・Context・Reducerの導入スライド

21 件(作成済み 15・導入不要 0・未作成 6・合計 75枚 / 15本)

レッスンの導入の索引へ戻る

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer1レッスン

なぜカスタムフックか

導入スライド 5

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

同じ12行が2つ並ぶ

トップスの一覧を、くつの一覧とまったく同じ書き方で足すとどうなるか見てください。

変わるのは category のところ1か所だけです。

部品取得コード
ShoesListcategory=shoes を fetch する12行
TopsListcategory=tops に変えただけの同じ12行

1 / 5

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

直す場所を数える

取得の置き場を切り替えて、再試行を足したときに直す場所がいくつになるか数えてください。

  • 2つに写すのままだと、直す場所が部品の数だけ増える
  • 再試行を足すを入れると、同じ1行が2つの部品にそのまま増える
  • useItems にまとめるへ切り替えると、直す場所は1か所のまま
同じ 12 行が 2 つ

2 / 5

重複が高くつく理由

写すのは一瞬でも、高くつくのはそのあとです。

書いたこと起きること

失敗したときの再試行を足したくなる

2か所とも直すことになる

取得中に別カテゴリへ切り替える対策を足す

ここも2か所とも直すことになる

片方だけ直して、もう片方を直し忘れる

画面によって挙動が違う、見つけにくい不具合になる

同じロジックがn個あると、直す手間もn倍になります。

3 / 5

見た目と、ロジックの違い

同じ見た目はコンポーネントにする、が今回も通用するか確かめます。

見た目が同じ2つ

コンポーネントに分ければ重複が消える

ロジックだけ同じ2つ

見た目は別。コンポーネントでは切り出せない

そっくりなのは見た目ではなく、state と useEffect の組み合わせのほうです。

4 / 5

考えてみよう外しても進めます

同じ取得ロジックが2つの部品にあります。コンポーネントに分けても解決しない理由はどれですか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer2レッスン

useItemsを作る

導入スライド 5

12行が呼び出し1行に

取得のコードを直接書いた場合と、useItems を呼ぶだけにした場合を比べてください。

ShoesList に直接書く

useEffect(() => { fetch("/api/items?category=shoes") .then((r) => r.json()) .then((d) => setItems(d)); }, []);

useItemsを呼ぶだけ

const { items, loading } = useItems("shoes");

12行あった取得の手続きが、呼び出し1行に変わります。

1 / 5

React状態管理:カスタムフック・Context・Reducer - useItemsを作る

返ってくる中身を見る

いまの状態を切り替えて、カスタムフックが返すオブジェクトの中身がどう変わるか確かめてください。

  • 届いたにすると、items に3件入り、loading が false になる
  • 失敗したで error も返すを外すと、0件のときと見分けが付かなくなる
  • 使う側は分割代入で受け取るだけでよい
useItems が返す 3 つ

2 / 5

よくある勘違い

よくある勘違いを先に潰しておきます。

書いたこと起きること

fetchItems のように use を付けずに名前を付ける

中でフックを呼んでいることに検査の道具が気付けない

useItems を2つの部品から呼ぶ

items が混ざると誤解する

JSX を返す関数だと思い込む

実際は state と、それを動かす仕組みを返すだけ

共有されるのはコードであって、state ではありません。

3 / 5

呼び出しごとに独立する

useItems はただの関数です。呼んだ部品ごとに別々の items と loading が返ります。

export function useItems(
useItems(ただの関数
category: string
) {
const [items, setItems] =
useState<Item[]>([]);
const [loading, setLoading] =
useState(true);
return { items, loading };
return { items, loading }値と道具を返す
}

結果

呼び出しitems
useItems("shoes")3件(くつ)
useItems("tops")2件(トップス)

4 / 5

考えてみよう外しても進めます

ShoesList と TopsList が両方 useItems を呼んでいます。一方の items が増えると、もう一方の items はどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer3レッスン

useFormを作る

導入スライド 5

stateを1つにまとめる

入力欄ごとに state を分けると、欄が増えるたびにハンドラも増えます。

欄ごとにstateを分ける

const [title, setTitle] = useState(""); const [price, setPrice] = useState("");

1つのオブジェクトにまとめる

const [values, setValues] = useState({ title: "", price: "" });

欄がいくつ増えても、まとめる state は1つのままです。

1 / 5

React状態管理:カスタムフック・Context・Reducer - useFormを作る

打った値の流れ

打っている欄を選んで文字数を増やし、打った値がどこへ流れるか見てください。

  • 打っている欄を切り替えると、色が付く行と入力欄の name が一緒に動く
  • 打った文字数を増やすと、values の行と入力欄の中身が同時に伸びる
  • 0文字のときは、まだ何も打っていない状態が出る
useForm が返す2つ

2 / 5

書き換えで事故る3つ

handleChange を書くとき、ここでよくつまずきます。

書いたこと起きること

...prev を広げずに上書きする

打った欄以外の値が消える

e.target.name ではなく決め打ちのキーで書き換える

他の入力欄を打ってもそのキーだけ書き換わる

reset で initial 以外の値を戻す

送信後に前回の入力が残ったままになる

[name] は変数の中身をキーにする書き方です。

3 / 5

useFormの中身

入力の書き換えを受け持つ handleChange まで書いた useForm です。

export function useForm(
initial: FormValues
) {
const [values, setValues] =
useState(initial);
function handleChange(
e: ChangeEvent<HTMLInputElement>
) {
const { name, value } = e.target;
setValues((prev) => ({
...prev, [name]: value,
}));
}
return { values, handleChange };
}

呼び出しと結果

打った操作values の中身
title欄に赤いくつと打つ{ title: "赤いくつ", price: "" }
続けてprice欄に3200と打つ{ title: "赤いくつ", price: "3200" }
title欄を消す{ title: "", price: "3200" }

4 / 5

考えてみよう外しても進めます

setValues の中で ...prev を書かずに { [name]: value } とだけ返すと、何が起きますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer4レッスン

フックのルール

導入スライド 5

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

2つのルールしかない

自分でフックを作れるようになると、置き場所を自分で決めることになります。

この2つを守れば、置き場所で困りません。

ルール内容
呼ぶ場所いちばん上の階層で呼ぶ。if や for の中では呼ばない
呼ぶ相手コンポーネントか、use で始まる名前の関数の中だけ

1 / 5

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

順番が入れかわる瞬間

描画の回を1回目から2回目に切り替えて、1番目の棚に何が入るか確かめてください。

  • 2回目にすると、1番目の棚は別の呼び出しの値を受け取ってしまう
  • if の中のフックは呼ばれない回ができ、数がそろわなくなる
  • フックを if の外に出すを入れると、2回目でもそれぞれの値に戻る
フックを呼ぶ順番

2 / 5

壊れ方は静かに始まる

条件がずっと真のあいだは何事も無く動くので、気づきにくいまま壊れます。

書いたこと起きること

フックより前に return を置く

その回だけ呼ぶ数が減り、同じ壊れ方が起きる

use で始まらない名前でフックを呼ぶ

検査の道具が見分けられず、警告すら出ない

条件が真のあいだだけ動かして満足する

あとで条件を変えた日に、別の場所が壊れる

条件はフックを囲むのではなく、フックの中に入れます。

3 / 5

条件はフックの中に

同じ特定のときだけ処理したいでも、書く位置で結果が変わります。

フックを囲む

if (category !== "") { useEffect(() => { fetch(url); }, [category]); }

フックの中で分ける

useEffect(() => { if (category === "") return; fetch(url); }, [category]);

useEffect は毎回同じ回数だけ呼ばれ、中身だけが変わります。

4 / 5

考えてみよう外しても進めます

フックを呼ぶ関数の名前を use で始めなくても動くことがあります。それでも use で始める理由は何ですか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer5レッスン

フックに型を付ける

導入スライド 5

戻り値に名前を付ける

戻り値に名前が無いと、使う側は綴りを間違えても気づけません。

型を書かない

export function useItems( category: string ): any { return { items, loading, error }; }

戻り値に名前を付ける

export function useItems( category: string ): UseItemsResult { return { items, loading, error }; }

名前を付けると、使う側の綴り間違いをその場で止められます。

1 / 5

React状態管理:カスタムフック・Context・Reducer - フックに型を付ける

山かっこを外すと

山かっこの型を外して、返ってくる型と打ち間違いの扱いを比べてください。

  • 型を渡すと、返ってくる中身の型まで決まる
  • 渡さないと型が決まらず、any のままになる
  • 打ち間違いを重ねると、型がある側だけその場で止まる
フックに渡す型

2 / 5

配列で返すと起きること

3つ以上を配列で返すと、順番を覚える負担が使う側に移ります。

書いたこと起きること

3つの値を配列で返す

使う側は順番を覚えないと読めず、1つ足すと全部ずれる

エラーを文字だけで返す

無いときも文字が必要になり、空文字でごまかしが生まれる

3つ以上を返すならオブジェクトにし、無い状態は null で表します。

3 / 5

3つの値に型を付ける

戻り値の3つに、名前と型を付けます。

export type UseItemsResult = {
items: Item[];
loading: boolean;
error: string | null;
string | nullまだ無い、を型で表す
};

戻り値の形

項目
itemsItem[]
loadingboolean
errorstring | null

4 / 5

考えてみよう外しても進めます

フックが3つの値を返すとき、配列とオブジェクトのどちらで返すべきですか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer6レッスン

つくる - フック化完了

導入スライド未作成
React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer7レッスン

第4章クイズ

導入スライド未作成
React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer8レッスン

バケツリレーの限界

導入スライド 5

4段のバケツリレー

テーマを App から PriceTag まで運ぶには、途中の2つにも受け取って渡してもらう必要があります。

App

theme を dark に決める

ItemList

受け取った theme をそのまま渡す

ItemCard

受け取った theme をそのまま渡す

PriceTag

受け取った theme を価格の見た目に使う

1 / 5

React状態管理:カスタムフック・Context・Reducer - バケツリレーの限界

値が下りていく道

どこまで渡したかを動かして、値が下りていく道を追ってください。

  • 運ぶ値が theme でも user でも、通る道の作りは同じ
  • List が渡し忘れるを入れると、そこから下は受け取れなくなる
  • 止まった先はエラーにならず、ただ何も来ないままになる
props のバケツリレー

2 / 5

使わないのに型に書く

ItemList は theme を自分では使いませんが、下に渡すために型にも呼び出しにも書きます。

function ItemList(
{ items, theme }: ItemListProps
theme自分では使わない
) {
return (
<ItemCard theme={theme} />
);
}

3 / 5

増えると起きること

動くには動きますが、段や共有したい値が増えると辛さが膨らみます。

書いたこと起きること

段が5段10段と深くなる

渡し忘れた1か所を探すのに時間が溶ける

文字サイズも共有したくなる

また全部の段に足すことになる

ItemList を別の場所で使い回す

要らない theme まで渡す羽目になる

途中の部品が、テーマを運ぶだけの通り道にされています。

4 / 5

考えてみよう外しても進めます

ItemCard で theme={theme} を書き忘れると、PriceTag はどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer9レッスン

Contextを作る

導入スライド 5

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

箱を作る2つの情報

createContext で箱を作るとき、山かっこと丸かっこの2つを書きます。

createContext<Theme>("light") の1行に、この2つが両方入っています。

書く場所意味
山かっこ箱に入る値の型を指定する
丸かっこProvider に包まれていない部品が受け取る既定値

1 / 5

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

Providerが囲む範囲

Provider で包む段数を動かして、どこまで dark が届くか確かめてください。

  • 包む段数を増やすと、囲みの中に入った部品が dark に変わる
  • 囲みの外に残った部品は、createContext に書いた既定値のままになる
  • 0段にすると、誰も包まれず全部が既定値のままになる
Provider が囲む範囲

2 / 5

Providerで包む宣言

配る範囲は、Provider で包んだ内側です。何段深くても関係ありません。

<ThemeContext.Provider value={theme}>
value={theme}包んだ内側に配る値
<div className="app">
<ItemList items={items} />
</div>
</ThemeContext.Provider>

3 / 5

考えてみよう外しても進めます

createContext の丸かっこに書いた light は、いつ使われますか。

選ぶと、この枚の中で答えと理由を確かめられます。

4 / 5

createContext で箱を作り、Provider で包んだ範囲に配る

取り出す useContext は次の回で扱います。この回はまだ配る宣言までです。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer10レッスン

useContextで使う

導入スライド 5

取り出す前と後

PriceTag が theme を受け取る2通りの書き方を見比べます。

propsで運ぶ

function PriceTag( { price, theme }: PriceTagProps ) { return <p>{theme}</p>; }

useContextで取る

function PriceTag({ price }: Props) { const theme = useContext(ThemeContext); return <p>{theme}</p>; }

props を1つ減らすだけで、途中の受け渡しが消えます。

1 / 5

React状態管理:カスタムフック・Context・Reducer - useContextで使う

上へ探しに行く

上へ探すを1段ずつ動かして、値がどこで見つかるか追ってください。

  • 上へ探すを動かすたびに、間の部品を素通りして進む
  • Provider に当たったところで、その value が返る
  • Provider を外すと当たらず、createContext に書いた既定値が返る
useContext が探しに行く

2 / 5

気づきにくい落とし穴

Provider が見つからないときの動きを確かめます。

書いたこと起きること

PriceTag を Provider の外側で呼ぶ

既定値が返るだけで、エラーにはならない

切り替えても価格の色が変わらない

たいてい Provider の外側で呼んでいるのが原因

止まらないぶん、原因にたどり着くのが遅れます。

3 / 5

あちこちで同じものを見たい少数のものに Context を使う

1つの画面だけで使う値は、これまでどおり props で足ります。

4 / 5

考えてみよう外しても進めます

useContext を呼んでも画面が変わらないとき、まず疑うべき原因は何ですか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer11レッスン

テーマの全体共有

導入スライド 5

配る値の中身

Provider の value に何を入れるかで、できることが変わります。

値だけ配る

value={theme}

値と関数を配る

value={{ theme, toggleTheme }}

読むだけの値では、切り替えるボタンが動きません。

1 / 5

React状態管理:カスタムフック・Context・Reducer - テーマの全体共有

1か所で全部が変わる

Provider に入れるテーマを切り替えて、いくつの部品が一緒に変わるか数えてください。

  • dark に切り替えると、包んだ中の部品が同時に変わる
  • value に theme だけを入れるをオンにすると、切り替えるほうが動かなくなる
  • 書き換えるのは value の1か所だけでよい
テーマの全体共有

2 / 5

自分の中は覗けない

App の中で useContext を呼ぶとどうなるか確かめます。

書いたこと起きること

App が ThemeProvider を描いている

App 自身は Provider の外側にいる

画面の本体を App の中に直接書く

useContext が既定値しか返さない

画面の本体は、Provider の中に置く部品へ切り出します。

3 / 5

読む値と切り替える関数はセットで value に入れる

配る人と使う人を分けると、押しても切り替わらない不具合を防げます。

4 / 5

考えてみよう外しても進めます

ThemeProvider を描いている App 自身の中で useContext を呼ぶと、何が返りますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer12レッスン

ユーザー情報の共有

導入スライド 5

居ないことを型にする

テーマは必ずどちらかの値でしたが、ユーザーはログアウトしていれば居ません。

export type User = {
id: string;
name: string;
};
export const UserContext =
createContext<User | null>(null);
| null居ないことを型で表す
(null)既定値も null

1 / 5

React状態管理:カスタムフック・Context・Reducer - ユーザー情報の共有

外に出すと何が返るか

Greeting の置き場所を Provider の外に切り替えて、返ってくる値を確かめてください。

  • Provider の外にすると、useContext は既定値の null を返す
  • null チェックを書くをオンにすると、落ちずに案内文を出せる
  • オフのまま外に出すと、画面は止まる
ユーザー情報の共有

2 / 5

早めに抜けて絞り込む

if で先に return すると、そのあとの行では user が null でないと分かります。

const user = useContext(UserContext);
if (user === null) {
user === null先に絞り込む
return <p>ログインしてください</p>;
}
return <p>{user.name} さん</p>;
user.nameここでは必ず居る

3 / 5

変わる理由で箱を分ける

テーマとユーザーは変わるきっかけが違うので、箱を分けたままにします。

1つの箱にまとめる

const AppContext = createContext({ theme: "light", user: null, });

変わるきっかけで分ける

const ThemeContext = createContext("light"); const UserContext = createContext<User | null>(null);

まとめると、テーマを切り替えただけでユーザーを見る部品まで描き直されます。

4 / 5

考えてみよう外しても進めます

UserContext の外側で useContext を呼ぶと、何が返りますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer13レッスン

つくる - Context整備

導入スライド未作成
React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer14レッスン

第5章クイズ

導入スライド未作成
React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer15レッスン

setStateの散らかり

導入スライド 5

3つの操作を持つカート

fleama のカートに要る操作は、入れる・数量を変える・外すの3つです。

カートに入れる

同じ商品があれば数量を1つ増やす

数量を変える

その行の数量だけを1つ増やす

カートから外す

その行を配列から外す

1 / 5

同じ計算が散らばる

handleQtyUp の中にも、数量を1つ増やす同じ計算が書いてあります。

function handleQtyUp(id: string) {
setCart((prev) =>
prev.map((line) =>
line.item.id === id
? { ...line,
qty: line.qty + 1 }
qty: line.qty + 1handleAdd にも同じ式がある
: line,
),
);
}

2 / 5

React状態管理:カスタムフック・Context・Reducer - setStateの散らかり

2か所に散った計算

カートのスニーカーの数量を10まで動かし、+ボタン側にも上限を書くを切り替えて確かめてください。

  • 数量を10にすると、カートに入れる側の上限10がまず効く
  • +ボタン側にも上限を書くをオンにするまで、+の数字だけが11に伸びる
  • オンにしてそろえても、同じ決まりを2か所に書いたことに変わりはない
setStateの散らかり

3 / 5

動くが読みにくい

動くには動きますが、読みにくいところが3つあります。

書いたこと起きること

同じ計算を handleAdd にも書く

決まりが増えるたび両方を直すことになる

更新の中身を部品の中に書く

別の画面から触るとき同じ関数を渡す羽目になる

操作が増えていく

handleAdd と handleQtyUp を目で拾わないと分からない

片方だけ直して事故る、という形で必ず表に出ます。

4 / 5

考えてみよう外しても進めます

上限10を handleAdd にだけ書いた状態で、数量10から+ボタンを押すとどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer16レッスン

useReducer

導入スライド 5

起きたことだけを渡す

押したその場で次の値を計算するのをやめ、起きたことだけを伝える形に変えます。

その場で次の値を渡す

setQty(qty + 1)

起きたことを渡す

dispatch("increase")

次の値を決める仕事は、reducer という1つの関数にまとめます。

1 / 5

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

3者の関係

dispatch で送る合図といまの数量を動かして、返ってくる次の数量を確かめてください。

  • dispatch で送る合図を increase・decrease・reset で切り替えられる
  • いまの数量を1にして decrease を送ると、1未満に減らさない決まりが効く
  • 第1引数のいまの状態と第2引数の起きたことから、次の状態だけが返る
useReducer

2 / 5

switchで遷移を並べる

qtyReducer の中に、起きたことごとの次の値をすべて並べます。

function qtyReducer(
qty: number,
qty: numberいまの状態
action: QtyAction,
action: QtyAction起きたこと
): number {
switch (action) {
case "increase":
return qty + 1;
case "decrease":
return qty > 1 ? qty - 1 : 1;
case "reset":
return 1;
}
}

3 / 5

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

1行に入った3つ

useReducer が返すのは、いまの状態と dispatch の組です。

書く場所中身
第1引数reducer 本体 (qtyReducer)
第2引数初期値 (1)
戻り値いまの状態と dispatch の組

4 / 5

考えてみよう外しても進めます

dispatch("increase") を読んだ人が、その場で分かることは何ですか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer17レッスン

Actionのunion型

導入スライド 5

文字だけでは足りない

前レッスンの action は文字だけでしたが、カートには商品や id という材料が要ります。

文字だけの action

dispatch("increase");

書類にした action

dispatch({ type: "ADD", item });

type で何が起きたかを書き、必要な材料を一緒に載せます。

1 / 5

3つのdispatchの形

ADD には商品そのもの、REMOVE と CHANGE_QTY には id が要ります。

dispatch({ type: "ADD", item });
item });ADD は商品ごと
dispatch({ type: "REMOVE",
id: "1" });
id: "1" });id だけで足りる
dispatch({ type: "CHANGE_QTY",
id: "1", qty: 3 });

2 / 5

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

型の口が塞ぐ場所

dispatch に渡す action を切り替えて、型がどこで止めるか確かめてください。

  • id を忘れた REMOVE は、dispatch に渡す前で止まる
  • 無い type を送っても、渡す前で止まる
  • type を string にすると検査が消え、カートまで素通りする
Actionのunion型

3 / 5

switchで絞り込まれる

action.type を switch にかけると、case の中でその形だけが読めます。

case "ADD":
return [...cart,
{ item: action.item, qty: 1 }];
action.itemADD の中だけ読める
case "REMOVE":
return cart.filter((line) =>
line.item.id !== action.id);
action.idREMOVE の中だけ読める

4 / 5

考えてみよう外しても進めます

action の type を string にすると何が起きますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer18レッスン

カートreducer

導入スライド 5

抜けは2つある

同じ商品を2回入れると行が2つ並び、数量を減らしても0のままの行が残ります。

やったこと起きること

同じ商品をもう一度 ADD する

行が2つ並んでしまう

CHANGE_QTY で0以下にする

行が0点のまま残る

1 / 5

見つけてから足す

ADD は、既に入っている行を探してから、増やすか足すかを決めます。

case "ADD": {
const found = cart.find((line) =>
line.item.id === action.item.id);
if (found) {
return cart.map((line) =>
line.item.id === action.item.id
? { ...line, qty: line.qty + 1 }
: line,
);
}
return [...cart,
{ item: action.item, qty: 1 }];
}

2 / 5

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

行と合計が一緒に動く

dispatch を1つずつ送って、行と合計がどう動くか見てください。

  • 決まりごと入りだと、同じ商品を足しても行は増えない
  • そのまま足すだけに切り替えると、同じ商品が2行に並ぶ
  • 数量を0にすると、行ごと外れるか残るかが変わる
カートの数量と合計

3 / 5

同じ配列を返すと止まる

cart.push で書き換えたあと同じ配列を返すと、React は変わっていないと見なします。

元の配列を書き換える

cart.push(line); return cart;

新しい配列を返す

return [...cart, line];

左は画面が更新されないのに、コンソールにも何も出ません。

4 / 5

考えてみよう外しても進めます

cart.push で行を足して cart をそのまま返すと、画面はどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer19レッスン

使い分け

導入スライド 5

React状態管理:カスタムフック・Context・Reducer - 使い分け

見分ける目安

useReducer を覚えると何でも寄せたくなりますが、目安があります。

fleama では検索欄が useState、カートが useReducer 向きです。

向き目安
useStateのまま値は1つ。置き換えるだけで、前の値を見なくてよい
useReducerへ1つの操作で複数の値が変わる。前の中身に更新が依る

1 / 5

React状態管理:カスタムフック・Context・Reducer - 使い分け

書く行数で比べる

更新する場所を増やして、書く行数がどちらで増えるか見てください。

  • 更新する場所を1か所に戻すと、useState のほうが短くなる
  • 更新の中身を検索欄の文字にすると、決まりごとが1行で済む
  • カートのまま場所を増やすと、reducer に1回書くだけで足りる
useState と useReducer の分かれ目

2 / 5

この更新の決まりごとを、他の人に説明する必要があるか

説明が要るなら、それは reducer に書き出せる決まりごとです。

3 / 5

混ぜすぎに注意

reducer に寄せすぎると、かえって読みにくくなることがあります。

書いたこと起きること

検索欄の1行の更新まで reducer にする

action の型を足す手間が増えるだけで、読みやすくならない

カートと検索欄を1つの大きな reducer にまとめる

関係の無い値まで同じ action で触ることになる

カートは reducer、検索欄は useState のまま。混ぜてよいのが結論です。

4 / 5

考えてみよう外しても進めます

検索欄に打った文字を持つ state は、useState と useReducer のどちらに向きますか。

選ぶと、この枚の中で答えと理由を確かめられます。

5 / 5

React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer20レッスン

つくる - カート完成

導入スライド未作成
React状態管理のコースサムネイル
React状態管理:カスタムフック・Context・Reducer21レッスン

第6章クイズ

導入スライド未作成