0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🧠 React Hooks総復習!useState・useEffect・useContext・useReducerで作るテーマ切り替えアプリ

Posted at

🎯 はじめに

Reactの主要なHooks(useState, useEffect, useContext, useReducer)を一通り学んだあと、
「実際にどう組み合わせて使うの?」と思う方も多いのではないでしょうか。

この記事では、これら4つを組み合わせて
「ダークモード/ライトモード切り替えアプリ」 を作成します。
UIの変化が目で見てわかるので、復習にも最適です!

🧩 前提条件

React(ViteやCRAなど)環境が整っていること

基本的なHooksの使い方を理解していること

CSSは最小限でOK(Tailwindなどは使いません)

🚀 今回の目標

フック 役割
useState 現在のテーマ(light/dark)を保持
useEffect localStorageとの同期処理
useContext テーマをアプリ全体で共有
useReducer 状態更新ロジックを整理・管理

🏗️ アプリ構成

src/
 ├─ App.jsx
 ├─ ThemeContext.jsx
 ├─ components/
 │   └─ ThemeToggler.jsx
 └─ index.css

🧱 1. ContextとReducerの作成(ThemeContext.jsx)

// src/ThemeContext.jsx
import React, { createContext, useReducer, useEffect } from "react";

// Context作成
export const ThemeContext = createContext();

const initialState = {
  theme: "light", // デフォルトはlight
};

// Reducer
function themeReducer(state, action) {
  switch (action.type) {
    case "TOGGLE_THEME":
      return {
        theme: state.theme === "light" ? "dark" : "light",
      };
    default:
      return state;
  }
}

// Providerコンポーネント
export const ThemeProvider = ({ children }) => {
  const [state, dispatch] = useReducer(themeReducer, initialState);

  // Effect localStorageとの同期
  useEffect(() => {
    const savedTheme = localStorage.getItem("theme");
    if (savedTheme) {
      dispatch({ type: "SET_THEME", payload: savedTheme });
    }
  }, []);

  useEffect(() => {
    localStorage.setItem("theme", state.theme);
    document.body.className = state.theme; // bodyにクラス付与
  }, [state.theme]);

  return (
    <ThemeContext.Provider value={{ state, dispatch }}>
      {children}
    </ThemeContext.Provider>
  );
};

💡 2. メインアプリ(App.jsx)

// src/App.jsx
import React from "react";
import { ThemeProvider } from "./ThemeContext";
import ThemeToggler from "./components/ThemeToggler";
import "./index.css";

function App() {
  return (
    <ThemeProvider>
      <div className="app-container">
        <h1>React Hooks 総復習</h1>
        <p>useState・useEffect・useContext・useReducerを使ってテーマを切り替え!</p>
        <ThemeToggler />
      </div>
    </ThemeProvider>
  );
}

export default App;

🔘 3. ボタンコンポーネント(ThemeToggler.jsx)

// src/components/ThemeToggler.jsx
import React, { useContext } from "react";
import { ThemeContext } from "../ThemeContext";

function ThemeToggler() {
  const { state, dispatch } = useContext(ThemeContext);

  return (
    <div>
      <button
        onClick={() => dispatch({ type: "TOGGLE_THEME" })}
        className="theme-button"
        style={{ color: state.theme === "light" ? "black" : "white" }}
      >
        現在のテーマ: {state.theme}(クリックで切替)
      </button>
    </div>
  );
}

export default ThemeToggler;

🎨 4. 最小限のCSS(index.css)

/* src/index.css */
body {
  margin: 0;
  font-family: sans-serif;
  transition: background-color 0.3s, color 0.3s;
}

body.light {
  background-color: #ffffff;
  color: #222;
}

body.dark {
  background-color: #222;
  color: #f5f5f5;
}

.app-container {
  text-align: center;
  padding: 40px;
}

.theme-button {
  padding: 10px 20px;
  cursor: pointer;
  border: 1px solid #888;
  background: none;
  font-size: 16px;
}

🧠 フックの関係図(概念的な図)

useReducer ──▶ state管理(theme: light/dark)


useContext ──▶ 子コンポーネントへ状態とdispatchを共有


useEffect ──▶ localStorageとDOM(body.className)を同期


useState ──▶ 内部的にはuseReducerの中で使われている形

🔍 ポイント解説

useReducer × useContext の組み合わせで「グローバル状態管理」が可能

useEffect は「副作用(localStorage, DOM操作)」に使う

useState を直接使わず、useReducerで一元管理することで拡張性UP

🏁 まとめ

Hooksは「単体で学ぶ → 組み合わせて使う」と理解が深まる

useReducerとuseContextの組み合わせは、Reduxのような構造を再現できる

useEffectで永続化を実現すると、アプリがぐっと実用的に!

🎬 最後に

ここまで理解できたら、次は「useMemo」と「useCallback」を一緒に学びましょう。
最後までご覧いただきありがとうございます。これからも勉強を兼ねて記事を投稿していきますので、温かく見守ってください。もし間違いなどございましたら、教えて頂けると幸いです。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?