Reactで簡単!useStateを使ったダークモード切り替え機能の実装

Reactでダークモードを実現するのは、見た目のデザインだけでなく、ユーザー体験を向上させる重要な取り組みです。特に、夜間や暗い環境での使用時に、視覚の負担を軽減できるダークモードは多くのアプリやウェブサイトで採用されています。本記事では、ReactのuseStateフックを使い、簡単にダークモードの状態管理と切り替え機能を実装する方法をわかりやすく解説します。基本的な設計から、実際のコード例、さらに応用的なトピックまでを網羅し、初心者でも実践できるように構成しています。

目次

ダークモードの概要とそのメリット

ダークモードとは、アプリケーションやウェブサイトの背景を暗い色調に変更することで、画面のコントラストを低く保ち、目の疲れを軽減するデザイン設定の一つです。このモードは、視覚的な快適さを提供するだけでなく、デバイスのバッテリー消費を抑えることにもつながります。

ダークモードのメリット

1. ユーザー体験の向上

夜間や暗い環境で画面を使用する際、明るい背景の光が目に負担をかけることがあります。ダークモードはその負担を軽減し、長時間の利用でも快適に操作できる環境を提供します。

2. バッテリーの節約

OLEDやAMOLEDディスプレイを使用しているデバイスでは、暗い色のピクセルが消費するエネルギーが少ないため、ダークモードを有効にすることでバッテリーの持続時間を延ばすことができます。

3. スタイリッシュなデザイン

ダークモードは洗練された印象を与え、特定のユーザー層に好まれる傾向があります。デザインの一環として、アプリケーションの見た目を引き締める効果もあります。

ダークモードは、単なる見た目の変更以上の価値を持っています。次節では、ReactのuseStateを使用してダークモードの状態を管理し、効率的に切り替えられる方法を学んでいきましょう。

useStateフックの基礎知識

Reactにおいて、コンポーネント内の状態を管理するための最も基本的な方法がuseStateフックです。状態(State)は、アプリケーションの動作を制御する重要な要素であり、ユーザーの操作やイベントに応じて変化します。

useStateの基本的な使い方

useStateは、Reactの関数型コンポーネント内で使用できるフックで、以下のようなシンタックスで使用します。

const [state, setState] = useState(initialValue);
  • state: 現在の状態を保持する変数。
  • setState: 状態を更新するための関数。
  • initialValue: 状態の初期値。

例: カウントアップ機能

以下は、ボタンをクリックするとカウントが増加する例です。

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>現在のカウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>カウントアップ</button>
    </div>
  );
}

export default Counter;

useStateのポイント

  1. 状態の初期値
    状態の初期値として、文字列、数値、配列、オブジェクト、関数など、任意のデータ型を使用できます。
  2. 状態の変更が再レンダリングをトリガー
    setState関数を使うと状態が更新され、コンポーネントが再レンダリングされます。
  3. useStateはフックであること
    Reactのフックルールに従い、関数型コンポーネントのトップレベルでのみ使用してください。ループや条件式の中では使用できません。

useStateは、Reactアプリケーションにおける動的なUIの基盤です。この基本知識をもとに、次節ではダークモードを切り替えるための状態管理を設計していきます。

ダークモードの状態管理の設計

ダークモードをReactで実装するには、useStateフックを使って状態を管理することが鍵です。ここでは、ダークモードの状態管理をどのように設計すれば効率的かつ柔軟に動作するかを解説します。

ダークモードの状態を定義する

ダークモードはON(有効)かOFF(無効)かという2つの状態を持つため、useStateで真偽値を使用します。

const [isDarkMode, setIsDarkMode] = useState(false);
  • isDarkMode: ダークモードが有効かどうかを示す状態。trueで有効、falseで無効。
  • setIsDarkMode: 状態を変更するための関数。

状態変更のトリガーを設計する

状態を切り替えるためには、ボタンやスイッチのクリックイベントをトリガーとして使用します。

function toggleDarkMode() {
  setIsDarkMode((prevMode) => !prevMode);
}

この関数では、現在の状態を反転させることでダークモードをON/OFFします。

状態に応じたUIの変更

ダークモードが有効な場合と無効な場合で、CSSクラスを動的に切り替えます。

<div className={isDarkMode ? "dark-mode" : "light-mode"}>
  <button onClick={toggleDarkMode}>
    {isDarkMode ? "ライトモードに切り替え" : "ダークモードに切り替え"}
  </button>
</div>
  • className: 状態に応じて適用されるクラス名を切り替えます。
  • ボタンのラベル: 現在の状態に応じて適切な表示をします。

設計のポイント

  1. 状態をアプリケーション全体で管理するか局所的に管理するか決定する
  • 小規模なアプリケーションでは、コンポーネントごとに管理。
  • 大規模なアプリケーションでは、コンテキストAPIやReduxを利用してグローバルに管理。
  1. 状態の永続化
    LocalStorageを利用して、ユーザーが選択したモードを保存することで、次回の訪問時にも同じ設定を適用可能にします。

次節では、この設計に基づいた実際のコードを構築し、ダークモード機能を実装していきます。

実装:ダークモードの基本的な構築方法

ここでは、Reactを使ってダークモードの切り替え機能を実装する具体的なコード例を紹介します。useStateを使用して状態管理を行い、動的にスタイルを適用します。

基本構造の作成

以下は、ダークモード切り替え機能を実現するシンプルなReactコンポーネントの例です。

import React, { useState } from "react";
import "./App.css"; // CSSファイルをインポート

function App() {
  // ダークモードの状態を管理
  const [isDarkMode, setIsDarkMode] = useState(false);

  // ダークモードの切り替え関数
  const toggleDarkMode = () => {
    setIsDarkMode((prevMode) => !prevMode);
  };

  return (
    <div className={isDarkMode ? "dark-mode" : "light-mode"}>
      <header className="App-header">
        <h1>{isDarkMode ? "ダークモード" : "ライトモード"}</h1>
        <button onClick={toggleDarkMode}>
          {isDarkMode ? "ライトモードに切り替え" : "ダークモードに切り替え"}
        </button>
      </header>
    </div>
  );
}

export default App;

CSSでスタイルを適用

ダークモードとライトモードのデザインをCSSで定義します。

/* App.css */
body {
  margin: 0;
  font-family: Arial, sans-serif;
}

.light-mode {
  background-color: #ffffff;
  color: #000000;
}

.dark-mode {
  background-color: #333333;
  color: #ffffff;
}

.App-header {
  text-align: center;
  padding: 50px;
}

button {
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
  margin-top: 20px;
  border: none;
  border-radius: 5px;
  color: white;
  background-color: #007bff;
}

button:hover {
  background-color: #0056b3;
}

コードの動作説明

  1. 状態管理
    isDarkModeでダークモードの状態を保持し、setIsDarkModeで状態を切り替えます。
  2. CSSクラスの動的変更
    classNameを状態に応じて動的に変更し、ダークモード用スタイルとライトモード用スタイルを切り替えます。
  3. ユーザーの選択を反映
    ボタンのラベルやページのデザインが、ダークモードの状態に応じて変化します。

機能の確認

この実装では、以下の機能が確認できます:

  • ボタンをクリックするたびにダークモードとライトモードが切り替わる。
  • 背景色と文字色が切り替えに応じて動的に変更される。

次節では、CSSのさらなる工夫と状態を永続化するための方法を解説します。

CSSでのダークモードデザインの適用

Reactアプリケーションでダークモードを実装する際、CSSを使ったスタイリングが重要です。適切なCSSを設定することで、状態に応じたダークモードの切り替えがスムーズに行えます。

CSSの基本的な適用方法

ダークモードとライトモードのスタイルを分けるには、classNameプロパティを状態に応じて切り替え、それぞれのモードに異なるスタイルを適用します。

/* App.css */

/* 全体のリセット */
body {
  margin: 0;
  font-family: Arial, sans-serif;
  transition: background-color 0.3s ease, color 0.3s ease; /* スムーズな切り替え */
}

/* ライトモードのスタイル */
.light-mode {
  background-color: #ffffff;
  color: #000000;
}

/* ダークモードのスタイル */
.dark-mode {
  background-color: #121212;
  color: #e0e0e0;
}

/* コンテンツの中央寄せ */
.App-header {
  text-align: center;
  padding: 50px;
}

/* ボタンのデザイン */
button {
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
  margin-top: 20px;
  border: none;
  border-radius: 5px;
  color: white;
  background-color: #007bff;
  transition: background-color 0.3s ease;
}

button:hover {
  background-color: #0056b3;
}

デザインの工夫

1. スムーズな切り替え

CSSのtransitionプロパティを使うことで、ダークモードとライトモードの切り替え時にスムーズなアニメーションを追加できます。

transition: background-color 0.3s ease, color 0.3s ease;

これにより、画面のちらつきを防ぎ、より洗練された印象を与えます。

2. 配色の工夫

  • ライトモード: 明るい背景色(#ffffff)と濃い文字色(#000000)を使用。
  • ダークモード: 暗い背景色(#121212)と柔らかい文字色(#e0e0e0)を使用。目に優しく、疲労を軽減します。

3. レスポンシブ対応

必要に応じて、メディアクエリを使用してデバイスのサイズに応じたスタイルを適用します。

@media (max-width: 768px) {
  .App-header {
    padding: 20px;
  }

  button {
    font-size: 14px;
    padding: 8px 16px;
  }
}

CSSクラスの切り替えの動作確認

  1. ダークモードとライトモードの状態で、背景色と文字色が正しく切り替わるか確認してください。
  2. ボタンのデザインがモード変更後も一貫して適用されているかを検証します。
  3. アニメーションがスムーズに動作するかをテストします。

次節では、ユーザーが選択したモードを保持する方法を解説し、ダークモードの利便性をさらに高めます。

ユーザーが選択したモードの保持

ダークモードの状態をユーザーのブラウザに保存することで、次回アクセス時にも選択内容を反映できます。ここでは、LocalStorageを使った実装方法を解説します。

LocalStorageを使った実装方法

LocalStorageは、ブラウザにデータを保存し、リロードやブラウザを再起動しても情報を保持する仕組みです。以下の手順でダークモードの状態を永続化します。

1. 初期状態をLocalStorageから取得

アプリケーションが読み込まれた際に、LocalStorageに保存された状態を確認し、初期値として設定します。

import React, { useState, useEffect } from "react";

function App() {
  // LocalStorageから状態を取得
  const [isDarkMode, setIsDarkMode] = useState(() => {
    const savedMode = localStorage.getItem("darkMode");
    return savedMode === "true"; // 文字列として保存されるため、booleanに変換
  });

  // ダークモードの切り替え関数
  const toggleDarkMode = () => {
    setIsDarkMode((prevMode) => !prevMode);
  };

  // 状態が変更されたときにLocalStorageに保存
  useEffect(() => {
    localStorage.setItem("darkMode", isDarkMode);
  }, [isDarkMode]);

  return (
    <div className={isDarkMode ? "dark-mode" : "light-mode"}>
      <header className="App-header">
        <h1>{isDarkMode ? "ダークモード" : "ライトモード"}</h1>
        <button onClick={toggleDarkMode}>
          {isDarkMode ? "ライトモードに切り替え" : "ダークモードに切り替え"}
        </button>
      </header>
    </div>
  );
}

export default App;

2. 状態の変更を監視して保存

useEffectフックを使用し、状態が変更された際にLocalStorageに新しい値を保存します。

useEffect(() => {
  localStorage.setItem("darkMode", isDarkMode);
}, [isDarkMode]);

動作確認

  1. ダークモードを有効または無効に切り替えた後、ブラウザをリロードして選択したモードが維持されるかを確認します。
  2. LocalStorageに正しく状態が保存されているかをブラウザの開発者ツールで検証します。

エラー処理の追加(オプション)

ブラウザによっては、LocalStorageが無効化されている場合があります。エラーを回避するためのチェックを追加します。

try {
  localStorage.setItem("darkMode", isDarkMode);
} catch (e) {
  console.error("LocalStorageに保存できません:", e);
}

永続化のメリット

  1. ユーザーフレンドリー: 毎回設定を変更する必要がなくなり、ユーザーの利便性が向上します。
  2. パーソナライズ体験: 選択した設定が保存されることで、より個人に最適化された体験を提供できます。

次節では、切り替え時のパフォーマンス最適化について解説し、さらなるユーザー体験の向上を目指します。

ダークモードのパフォーマンス最適化

ダークモードの切り替え機能は基本的な実装だけでなく、効率性やパフォーマンスにも配慮することで、より快適なユーザー体験を提供できます。ここでは、ダークモード切り替え時のパフォーマンス最適化方法を解説します。

1. 必要最小限の再レンダリング

ダークモード切り替え時にコンポーネント全体を再レンダリングしないようにするため、状態管理を工夫します。

Context APIを活用

アプリケーション全体でダークモードの状態を共有する際に、Context APIを使うとパフォーマンスを向上させることができます。

import React, { createContext, useContext, useState } from "react";

// コンテキストの作成
const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [isDarkMode, setIsDarkMode] = useState(false);

  const toggleDarkMode = () => {
    setIsDarkMode((prevMode) => !prevMode);
  };

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

// カスタムフックで簡単に状態を取得
export const useTheme = () => useContext(ThemeContext);

使用側のコンポーネント:

import React from "react";
import { useTheme } from "./ThemeContext";

function App() {
  const { isDarkMode, toggleDarkMode } = useTheme();

  return (
    <div className={isDarkMode ? "dark-mode" : "light-mode"}>
      <header className="App-header">
        <h1>{isDarkMode ? "ダークモード" : "ライトモード"}</h1>
        <button onClick={toggleDarkMode}>
          {isDarkMode ? "ライトモードに切り替え" : "ダークモードに切り替え"}
        </button>
      </header>
    </div>
  );
}

export default App;

2. CSS変数の活用

CSS変数を使用して、スタイルの切り替えを効率化します。これにより、JavaScriptの操作を最小限に抑え、切り替えを高速化できます。

:root {
  --background-color: #ffffff;
  --text-color: #000000;
}

.dark-mode {
  --background-color: #121212;
  --text-color: #e0e0e0;
}

body {
  background-color: var(--background-color);
  color: var(--text-color);
}

JavaScriptでクラスを切り替えるだけでスタイルが動的に適用されます。

3. 非同期処理の最適化

状態変更に伴う副作用処理(例: LocalStorageへの保存)が遅延を引き起こさないよう、非同期処理を活用します。

useEffect(() => {
  const saveThemePreference = async () => {
    try {
      localStorage.setItem("darkMode", isDarkMode);
    } catch (error) {
      console.error("テーマの保存に失敗しました:", error);
    }
  };

  saveThemePreference();
}, [isDarkMode]);

4. メモ化によるパフォーマンス向上

不要な再計算を防ぐために、useMemouseCallbackを使用して関数や値をメモ化します。

const toggleDarkMode = useCallback(() => {
  setIsDarkMode((prevMode) => !prevMode);
}, []);

5. 初期レンダリング時のフラッシュ防止

初期状態をCSSで適用し、JavaScriptが読み込まれる前にユーザーがライトモードのフラッシュを目にしないようにします。

<script>
  if (localStorage.getItem('darkMode') === 'true') {
    document.documentElement.classList.add('dark-mode');
  }
</script>

パフォーマンス最適化のメリット

  • 切り替え操作が高速化され、ユーザー体験が向上します。
  • 再レンダリングの最小化により、リソースの効率的な利用が可能になります。
  • アプリケーションのレスポンスが改善され、全体的な満足度が向上します。

次節では、ダークモードをさらに洗練させるための応用例として、トグルスイッチを使った切り替え機能を紹介します。

応用例:トグルスイッチを使った切り替え

ダークモード切り替えのUIをボタンからトグルスイッチに変更することで、より洗練されたデザインと直感的な操作感を提供できます。ここでは、トグルスイッチを実装する方法を紹介します。

トグルスイッチの実装

トグルスイッチは、見た目をカスタマイズしたチェックボックスとして構築するのが一般的です。以下のコードでは、ReactとCSSを使用してトグルスイッチを作成します。

1. トグルスイッチのHTML構造

function App() {
  const [isDarkMode, setIsDarkMode] = useState(false);

  const toggleDarkMode = () => {
    setIsDarkMode((prevMode) => !prevMode);
  };

  return (
    <div className={isDarkMode ? "dark-mode" : "light-mode"}>
      <header className="App-header">
        <h1>{isDarkMode ? "ダークモード" : "ライトモード"}</h1>
        <label className="toggle-switch">
          <input
            type="checkbox"
            checked={isDarkMode}
            onChange={toggleDarkMode}
          />
          <span className="slider"></span>
        </label>
      </header>
    </div>
  );
}

export default App;

2. トグルスイッチのCSSスタイル

以下のCSSを追加して、トグルスイッチの外観を整えます。

/* トグルスイッチ全体 */
.toggle-switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
}

/* 非表示のチェックボックス */
.toggle-switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

/* スライダー部分 */
.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  transition: 0.4s;
  border-radius: 34px;
}

/* スライダーの丸い部分 */
.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  transition: 0.4s;
  border-radius: 50%;
}

/* チェックされたときのスタイル */
input:checked + .slider {
  background-color: #007bff;
}

input:checked + .slider:before {
  transform: translateX(26px);
}

トグルスイッチの動作

  1. トグルスイッチをクリックするとonChangeイベントが発火し、toggleDarkMode関数が呼び出されます。
  2. isDarkModeの値が更新され、切り替えに応じてclassNameが変更されます。
  3. CSSで定義したスタイルにより、背景色と文字色が切り替わります。

トグルスイッチの利点

  • 視覚的に直感的: スイッチの動きがダークモードの切り替えを視覚的に分かりやすくします。
  • デザインの一貫性: トグルスイッチは多くのアプリケーションやプラットフォームで採用されているため、ユーザーにとって親しみやすいです。

トグルスイッチにさらなる機能を追加

  1. アニメーションの強化
    スイッチの動きや背景色の切り替えにアニメーションを追加することで、より洗練された操作感を実現します。
  2. アクセシビリティ対応
    トグルスイッチにaria-labelを設定し、スクリーンリーダーのユーザーにも使いやすくします。
<input
  type="checkbox"
  checked={isDarkMode}
  onChange={toggleDarkMode}
  aria-label="ダークモード切り替え"
/>

トグルスイッチを活用することで、ダークモードの切り替え機能がより魅力的で使いやすくなります。次節では、これまでの内容を振り返り、記事をまとめます。

まとめ


本記事では、Reactでダークモードを実装する方法について、基礎から応用までを詳しく解説しました。useStateを使った状態管理を中心に、CSSによるスタイリング、LocalStorageを用いた状態の永続化、Context APIを利用した効率的な管理、さらにはトグルスイッチを使った応用的な切り替え機能も紹介しました。

ダークモードは、視覚的な快適さやバッテリー節約といった利点があり、多くのユーザーにとって魅力的な機能です。本記事の内容を参考に、あなたのReactプロジェクトにダークモードを実装し、ユーザー体験を向上させてみてください。

コメント

コメントする

目次