Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Redux と状態管理
Search
Jeongmin LEE
February 25, 2026
Programming
22
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Redux と状態管理
Jeongmin LEE
February 25, 2026
More Decks by Jeongmin LEE
See All by Jeongmin LEE
TypeScript のコンパイル
gardensky511
0
66
【2025年新卒研修】 React・Next.js は何であるのか
gardensky511
0
140
Webレンダリング最適化の道
gardensky511
0
57
Webレンダリング技術の進化と課題
gardensky511
0
100
Promise と async/await
gardensky511
0
63
シングルな Javascript の非同期処理
gardensky511
0
200
集合で理解する Typescript
gardensky511
1
340
Javascript のデータ型 プリミティブ型・オブジェクト
gardensky511
0
180
Other Decks in Programming
See All in Programming
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
290
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
210
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
12
4.4k
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
160
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
800
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
130
ふつうのFeature Flag実践入門
irof
8
4.1k
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
14
5.7k
dRuby over BLE
makicamel
2
380
The NotImplementedError Problem in Ruby
koic
1
890
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.3k
1B+ /day規模のログを管理する技術
broadleaf
0
110
Featured
See All Featured
Crafting Experiences
bethany
1
190
What's in a price? How to price your products and services
michaelherold
247
13k
Claude Code のすすめ
schroneko
67
230k
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
400
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
230
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
320
Are puppies a ranking factor?
jonoalderson
1
3.6k
Context Engineering - Making Every Token Count
addyosmani
9
980
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
72
40k
Transcript
Redux と状態管理
職業 自己紹介 韓国人です。大学時代にはげしくアニメ オタクをやってて日本語が上手くなりま した。 フロントエンドエンジニア(2020/11 ~) React、Typescript メインでやってます
CONTENTS 1. そもそも状態とは 2. Redux とは 3. Redux Toolkit の登場
4. Redux 使用時の注意点
1. そもそも状態とは
状態(state)は、UIや挙動を決めるデータ 検索条件モーダル非表示 条件の変更ボタンクリック 検索条件モーダル表示
状態(state)は、UIや挙動を決めるデータ 検索条件モーダル非表示 条件の変更ボタンクリック 検索条件モーダル表示 showModal が false だから モーダルを表示しない showModal
を true に更新 showModal が true だから モーダルを表示する
状態(state)は、UIや挙動を決めるデータ 検索条件モーダル非表示 条件の変更ボタンクリック 検索条件モーダル表示 showModal が false だから モーダルを表示しない showModal
を true に更新 showModal が true だから モーダルを表示する React の思想: UI = f(state) 状態(state)が変わると UI が再計算される
ローカル状態とグローバル状態 ローカル状態(Local State) あるコンポーネント(または近い範囲)だけで完結する状態 Component Component Component Component Component Component
Component Component Component Component 状態が特定のコンポーネント (+近い子孫)でだけ使われる React の場合 useState で 管理することが多い 例)テキスト検索UIで文字入力したら下にサジェスト表示する場合など
ローカル状態とグローバル状態 グローバル状態(Global State) 複数箇所で共有され、離れたコンポーネント間でも一貫して扱いたい状態 例)商品を気になる登録したら、ヘッダーにも商品概要にもスティッキーフッターにも反映される場合など Component Component Component Component Component
Component Component Component Component Component 状態が横断的に色んな コンポーネントで使われる グローバル状態を共有する 仕組みが必要になってくる
グローバル状態は管理がとても大変 グローバル状態関連バグの一例(チャットアプリの場合) 1. ヘッダーのメッセージアイコンに「🔴1(未読あり)」がついている 2. クリックしてメッセージを読み、既読にする 3. 通知バッジの「🔴1」が消えない、もしくは一度消えたのに別の操作をするとまた復活する
1. ヘッダーのメッセージアイコンに「🔴1(未読あり)」がついている 2. クリックしてメッセージを読み、既読にする 3. 通知バッジの「🔴1」が消えない、もしくは一度消えたのに別の操作をするとまた復活する message.isRead メッセージが既読か未読か管理する thread.hasUnread このスレッドに未読があるか管理
header.unreadCount 未読数はいくつあるか管理 原因:特定の値を複数個所で「別々の状態」としてもっていてた メッセージモデル スレッドモデル ヘッダーバッジモデル グローバル状態関連バグの一例(チャットアプリの場合) グローバル状態は管理がとても大変
1. ヘッダーのメッセージアイコンに「🔴1(未読あり)」がついている 2. クリックしてメッセージを読み、既読にする 3. 通知バッジの「🔴1」が消えない、もしくは一度消えたのに別の操作をするとまた復活する message.isRead メッセージが既読か未読か管理する thread.hasUnread このスレッドに未読があるか管理
header.unreadCount 未読数はいくつあるか管理 原因:特定の値を複数個所で「別々の状態」としてもっていてた メッセージモデル スレッドモデル ヘッダーバッジモデル ユーザーがメッセージを既読にしました! 「このメッセージは既読」更新✅ 「スレッドに未読なし」更新✅ 更新漏れ ❌ ヘッダーに未読が残ったまま グローバル状態関連バグの一例(チャットアプリの場合) グローバル状態は管理がとても大変
🤯
グローバル状態をいい感じに管理するためのライブラリ Redux (2015) Mobx (2015) Zustand (2019) Jotai (2020) Recoil
(2020) ※ 各ライブラリーの思想はそれぞれ違う ※ クライアントの状態管理ライブラリだけに絞ってる(サーバー側の状態管理の話は省略する) XState (2018)
None
Redux の回なので Redux の話をします
2. Redux とは
Redux とは 予測可能で、メンテ可能なグローバル状態管理のためのJSライブラリ
Redux とは 予測可能で、メンテ可能なグローバル状態管理のためのJSライブラリ まず Redux のグローバル状態管理について説明する
Redux における状態管理の登場人物 Store グローバル状態をすべて保管している場所(状態ツリーを持つオブジェクト) メッセージ一覧が状態として store に保存されている 例で未読のメッセージを既読にする 場合を想定してみます
Redux における状態管理の登場人物 Store グローバル状態をすべて保管している場所(状態ツリーを持つオブジェクト) メッセージ一覧が状態として store に保存されている 例で未読のメッセージを既読にする 場合を想定してみます ❗Store
は1つであるべき❗ 状態があちこちに散らばらないため、更新漏れが防止できる Redux 3原則その1. 真実の置き場は1つ
Redux における状態管理の登場人物 Store グローバル状態をすべて保管している場所(状態ツリーを持つオブジェクト) メッセージ一覧が状態として store に保存されている 例で未読のメッセージを既読にする 場合を想定してみます やりたいこと:
id が “m1” のメッセージを既読にしたい
Redux における状態管理の登場人物 Action 何が起きたかを表すただのオブジェクト 「メッセージ id が ‘m1’ のメッセージを既読にする」という内容の依頼書
Redux における状態管理の登場人物 Action 何が起きたかを表すただのオブジェクト 「メッセージ id が ‘m1’ のメッセージを既読にする」という内容の依頼書 何をするかを表す
type フィールドが必須 (定数で定義することが多い)
Redux における状態管理の登場人物 Action 何が起きたかを表すただのオブジェクト 「メッセージ id が ‘m1’ のメッセージを既読にする」という内容の依頼書 この
Action を返す関数を Action Creator と言う
Redux における状態管理の登場人物 Action 何が起きたかを表すただのオブジェクト 「メッセージ id が ‘m1’ のメッセージを既読にする」という内容の依頼書 ❗状態は直接変更しない❗
状態を変更する唯一の方法は Action を発行することである state が変更される度に Action が残るので、追跡できる Redux 3原則その2. 状態は読み取り専用
Redux における状態管理の登場人物 Action 何が起きたかを表すただのオブジェクト 「メッセージ id が ‘m1’ のメッセージを既読にする」という内容の依頼書 ❗状態は直接変更しない❗
状態を変更する唯一の方法は Action を発行することである state が変更される度に Action が残るので、追跡できる Redux 3原則その2. 状態は読み取り専用 例えると、、 会社のお金が金庫に全部現金で保管しているとして、 各部署が勝手に予算をそれぞれに持っていってる感じ (誰がいついくらもっていたかわからなくなってカオス)
Redux における状態管理の登場人物 Dispatch Action を Store に送る関数 さきほど作った Action を
Dispatch 関数で Store に送る
Redux における状態管理の登場人物 Reducer Action を受け取って変更が反映された新しい状態を返す関数
Redux における状態管理の登場人物 Reducer Action を受け取って変更が反映された新しい状態を返す関数 ❗Reducer は純粋関数であるべき❗ 同じ入力なら同じ出力なのでテストできる、予測できる
Redux における状態管理の登場人物 Reducer Reducer が純粋関数の場合 従来の状態を INPUT すると新しい状態を返す 従来の状態 {
count: 1 } Reducer count に1を 足した状態を返す 新しいの状態 { count: 2 } Reducer に同じ state を渡して 100回実行しても常に { count: 2 } を返す ※ 入力が変わらないので、次の状態は入力だけで決まる(=予測しやすい) ※ 入力が変わらないので、テストが独立する(=テストしやすい)
Redux における状態管理の登場人物 Reducer Reducer が純粋関数の場合 従来の状態を INPUT すると新しい状態を返す 従来の状態 {
count: 1 } Reducer count に1を 足した状態を返す 新しいの状態 { count: 2 } Reducer に同じ state を渡して 100回実行しても常に { count: 2 } を返す ※ 入力が変わらないので、次の状態は入力だけで決まる(=予測しやすい) ※ 入力が変わらないので、テストが独立する(=テストしやすい) 元のオブジェクトは変えずに、新しいオブジェクトを作って 変更を表現することをイミュータブル(immutable)と言う
Redux における状態管理の登場人物 従来の状態を INPUT すると従来の状態が変わる 従来の状態 { count: 1 }
Reducer 従来の count に1を足す Reducer Reducer が純粋関数ではない場合
Redux における状態管理の登場人物 Reducer Reducer が純粋関数ではない場合 Reducer に同じ state を渡して 100回実行したら
{ count: 101 } になる ※ 入力が変わるので、次の状態が“過去”に依存する(=状態の次を予測するために過去の処理回数や順番など気にしないといけない) ※ 入力が変わるので、前のテストの結果が次のテストに影響する(=テストしづらい) 従来の状態を INPUT すると従来の状態が変わる 従来の状態 { count: 2 } Reducer 従来の count に1を足す
Redux における状態管理の登場人物 Reducer Reducer が純粋関数ではない場合 Reducer に同じ state を渡して 100回実行したら
{ count: 101 } になる ※ 入力が変わるので、次の状態が“過去”に依存する(=状態の次を予測するために過去の処理回数や順番など気にしないといけない) ※ 入力が変わるので、前のテストの結果が次のテストに影響する(=テストしづらい) 従来の状態を INPUT すると従来の状態が変わる 従来の状態 { count: 2 } Reducer 従来の count に1を足す 元のオブジェクトを同じ参照のまま中身を変えることを ミュータブル(mutable)と言う 参照うんうんの詳しい話は↓のスライドを参考にしよう
Redux における状態管理の登場人物 Reducer Action を受け取って変更が反映された新しい状態を返す関数 ❗Reducer は純粋関数であるべき❗ 同じ入力なら同じ出力なのでテストできる、予測できる Redux 3原則その3.
変更は純粋関数で行われる
Redux における状態管理の登場人物 • Store: グローバル状態をすべて保管している場所(オブジェクト) • Action: 何が起きたかを表す依頼書(オブジェクト) • Dispatch:
Action を Store に送る(関数) • Reducer: Action を受け取り変更が反映された新しい状態を返す(関数) Redux の3原則 • Store は1つであるべき: 状態があちこちに散らばらないため、更新漏れが防止できる • 状態は読み取り専用: 状態を変更する唯一の方法は Action を発行すること • Reducer は純粋関数であるべき: 同じ入力なら同じ出力なのでテストできる、予測できる
状態更新の流れ Component Component Component View 1. 状態更新イベントが発生する
状態更新の流れ Store Component Component Component View Action Dispatch 2. Action
を Dispatch する Event Handler 1. 状態更新イベントが発生する
状態更新の流れ Store Component Component Component View Action Dispatch 2. Action
を Dispatch する Event Handler Reducer State 3. Reducer が Action を受け取って 新しい状態を生成・Store に反映する 1. 状態更新イベントが発生する
状態更新の流れ Store Component Component Component View Action Dispatch 2. Action
を Dispatch する Event Handler Reducer State 3. Reducer が Action を受け取って 新しい状態を生成・Store に反映する 4. Store の状態を参照している すべてのUIに状態変更が反映される 1. 状態更新イベントが発生する
状態更新の流れ Store Component Component Component View Action Dispatch 2. Action
を Dispatch する Event Handler Reducer State 3. Reducer が Action を受け取って 新しい状態を生成・Store に反映する 4. Store の状態を参照している すべてのUIに状態変更が反映される 1. 状態更新イベントが発生する 状態が変わる場所・理由・ルールが決まってる → いつ・どこで・何の状態が変わったか追跡できる
3. Redux Toolkit の登場
Redux ってボイラープレートがめちゃくちゃ激しい ボイラープレート: 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード
Redux ってボイラープレートがめちゃくちゃ激しい ボイラープレート: 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード ※ 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード Action の数分 Action Type
を定義する (しかも非同期処理と状態を紐づく場合 pending、 success、fail の3つセットで定義必要)
Redux ってボイラープレートがめちゃくちゃ激しい ボイラープレート: 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード ※ 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード そして Action の数分 Action
Creator 定義
Redux ってボイラープレートがめちゃくちゃ激しい ボイラープレート: 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード ※ 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード そして Action の数分 Reducer
定義 ... 多すぎてわけわからない
Redux ってボイラープレートがめちゃくちゃ激しい ボイラープレート: 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード ※ 機能実現のために多くの箇所に繰り返し記述する定型的なテンプレートコード あまりにもやばすぎて Redux 公式が Redux
Toolkit を発表 もっと手軽に Redux を書けるようにした
Redux Toolkit で slice 登場
Dispatch するとき自動生成された Action Creator 呼び出すだけ Action Type、Action Creator 自動生成してくれる name
と Reducer 名を組み合わせて Action Type を自動生成してくれる (この例だと “messages/MARK_AS_READ_REQUEST”) Action Creator も自動生成してくれる Redux Toolkit で slice 登場
内部的な Immer 採用により ... 地獄から解放 Redux Toolkit で slice 登場
※ Immerとは 直接データを変える書き方(ミューテーション)をしても、 裏側で安全な新しいコピー(イミュータブルな状態)を作ってくれるライブラリ このように状態を直接書き換える書き方をし ても、裏側で勝手にミュータブル(INPUTを直 接変更せず新しい状態を返す)にしてくれる
ということで Redux Toolkit 登場 (2019) 以降は Redux 使うなら Redux Toolkit
を採用することが標準
4. Redux 使用時の注意点
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる 複数箇所で共有され、離れたコンポーネント間でも一貫して扱いたい状態 例)商品を気になる登録したら、ヘッダーにも商品概要にもスティッキーフッターにも反映される場合など Component
Component Component Component Component Component Component Component Component Component Store ✅横断的に使われる状態を Store に入れて管理しよう
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる ❌特定の箇所で使われる状態を Store に入れて管理しよう
あるコンポーネント(または近い範囲)だけで完結する状態 Component Component Component Component Component Component Component Component Component Component 例)テキスト検索UIで文字入力したら下にサジェスト表示する場合など Store useState で事足り案件をわざわざ Action 発行してそれを Dispatch して Reducer 作成して Store に格納する意味が ないし、無駄にアプリケーションが複雑になる
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる Component Component Component
Component Component Component Component Component Component Component Store Front-end Back-end Database request response ❌APIから取得したデータも全部 Store に入れる
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる Component Component Component
Component Component Component Component Component Component Component Store Front-end Back-end Database request response ❌APIから取得したデータも全部 Store に入れる APIレスポンスのDBのコピー(DBが真実)
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる Component Component Component
Component Component Component Component Component Component Component Store Front-end Back-end Database request response APIレスポンスのDBのコピー(DBが真実) ❌APIから取得したデータも全部 Store に入れる → 非同期で取得(成功・失敗・ローディング) → 時間が経つと古くなる(再取得が必要) → キャッシュが必要になる可能性有 → …
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる Component Component Component
Component Component Component Component Component Component Component Store Front-end Back-end Database request response APIレスポンスのDBのコピー(DBが真実) ❌APIから取得したデータも全部 Store に入れる → 非同期で取得(成功・失敗・ローディング) → 時間が経つと古くなる(再取得が必要) → キャッシュが必要になる可能性有 → … Redux はクライアント状態管理のライブラリな ので、それでサーバー状態をやろうとするとやや こしくなるし、無駄に Store が膨らむ サーバー状態: 真実がDB/APIにあるデータ クライアント状態: 真実がFEにあるデータ
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる Component Component Component
Component Component Component Component Component Component Component Store Front-end Back-end Database request response APIレスポンスのDBのコピー(DBが真実) ❌APIから取得したデータも全部 Store に入れる → 非同期で取得(成功・失敗・ローディング) → 時間が経つと古くなる(再取得が必要) → キャッシュが必要になる可能性有 → … サーバー状態(真実がDB/APIにあるデータ)は専用の ライブラリで管理したほうが良い
なにもかもすべて全部 Store に入れない Redux はグローバル状態管理ライブラリなので、グローバル状態にすべきものだけを Store に入れる 今日話した内容全部忘れてもいいのでこれだけは覚えて帰ってほしい
ご清聴ありがとうございました