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

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分

テーマの全体共有

テーマの全体共有

切り替えられるテーマにする

ここまでのテーマは const theme: Theme = "dark" と書いた固定値でした。本物のダークモードは、ボタンを押すと切り替わります。切り替わるものは state です。

問題は、その state をどこに置くかです。App に置くと、切り替える関数も App にあります。それをボタンまで届けるのに、また props のバケツリレーが始まります。

Provider ごと部品にする

そこで、state と切り替えの関数をまとめて持つ部品を作ります。中身を children で受け取り、Provider で包んで返すだけの部品です。

TypeScript (JSX)

export function ThemeProvider({ children }: ThemeProviderProps) { const [theme, setTheme] = useState<Theme>("light"); const toggleTheme = () => { setTheme(theme === "light" ? "dark" : "light"); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); }

value にオブジェクトを入れて、値と関数を一緒に配るのがこつです。読むほうだけ配ると、切り替えたい部品が困ります。

箱の型もそれに合わせます。

TypeScript (JSX)

export type ThemeContextValue = { theme: Theme; toggleTheme: () => void; }; export const ThemeContext = createContext<ThemeContextValue>({ theme: "light", toggleTheme: () => {}, });

既定値の toggleTheme は何もしない関数です。Provider の外で呼ばれても落ちないようにするための置き石だと思ってください。

使う側は分割代入で

TypeScript (JSX)

const { theme, toggleTheme } = useContext(ThemeContext);

これでボタンの onClick に toggleTheme をそのまま渡せます。ヘッダーも価格も、同じ箱を覗くだけで足並みがそろいます。

自分が置いた Provider の中は覗けない

一つ落とし穴があります。<ThemeProvider> を描いている App 自身は、その Provider の外側にいます。App の中で useContext を呼んでも既定値しか返りません。

だから、画面の本体は App の中に直接書かず、Screen のような部品に切り出して Provider の中に入れます。値を配る人と、値を使う人を分けるのが Provider 設計の基本形です。

演習

ThemeProvider を作り、ボタンで画面全体のテーマを切り替えます。

ヒント

value={{ theme, toggleTheme }} のように、中かっこが二重になります

受け取るときは const { theme, toggleTheme } = useContext(ThemeContext); です

App の中で useContext を呼んでも既定値しか返りません。画面の本体は Screen に切り出します

PriceTag の受け取り方も、分割代入に直す必要があります

App.tsx
ThemeContext.tsx
プレビュー

できているか

  • 最初はライトテーマになっている
  • 価格にもライトテーマが届いている
  • 切り替えボタンがある
  • ボタンを押すと画面全体がダークになる
  • もう一度押すとライトに戻る
  • テーマを state で持っている
  • ThemeProvider を切り出している
  • App が ThemeProvider で包んでいる
エディタを読み込んでいます