Reactでメディアクエリを活用したダーク/ライトモード切り替え完全ガイド

Reactアプリケーションのユーザーエクスペリエンスを向上させるためには、ダークモードとライトモードを動的に切り替える機能が欠かせません。近年、多くのアプリケーションがこのテーマ切り替え機能を標準として採用しています。この機能はユーザーの快適性を向上させるだけでなく、アクセシビリティの観点でも重要です。本記事では、Reactを使用してメディアクエリを活用し、ユーザーのデバイス設定に応じて自動的にテーマを切り替える方法を詳しく解説します。最終的には、ダークモードとライトモードを自由に切り替える洗練されたアプリを構築するスキルを習得できます。

目次

メディアクエリの基本と仕組み

メディアクエリは、CSSで利用される技術で、画面サイズやデバイスの特性に応じてスタイルを適用するために使われます。この仕組みを利用することで、画面の幅、高さ、解像度、照度設定などに基づいて異なるスタイルを適用できます。

メディアクエリの基本構文

以下は、メディアクエリの基本的なCSS構文の例です:

@media (prefers-color-scheme: dark) {
  body {
    background-color: black;
    color: white;
  }
}

@media (prefers-color-scheme: light) {
  body {
    background-color: white;
    color: black;
  }
}

この例では、ユーザーのデバイスがダークモードまたはライトモードに設定されている場合、それに応じた背景色と文字色が適用されます。

Reactでのメディアクエリの応用

CSSだけでなく、Reactアプリケーション内でもJavaScriptを使用してメディアクエリを検出し、動的なUI変更を行うことができます。これにより、スタイリングだけでなく、コンポーネントの表示やロジックにもメディアクエリの条件を適用できます。

例:デバイスのテーマ設定の取得

ユーザーのデバイス設定を取得するJavaScriptの例:

const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;

console.log(isDarkMode ? 'Dark mode is enabled' : 'Light mode is enabled');

このコードは、ユーザーのデバイス設定に基づいて現在のテーマモードを判定します。

テーマ切り替えにおけるメディアクエリの利点

  1. ユーザー設定に対応:デバイスのダークモード設定を尊重し、シームレスなテーマ切り替えを提供できます。
  2. アクセシビリティの向上:環境に応じたスタイル変更が可能で、視認性を向上させます。
  3. コードの一貫性:CSSとJavaScriptで共通の条件を適用することで、スタイルとロジックの整合性を保てます。

メディアクエリは、ユーザーエクスペリエンスを向上させるための強力なツールであり、Reactアプリケーションのテーマ切り替え機能に最適です。次のセクションでは、Reactでのメディアクエリの具体的な実装方法について説明します。

Reactでメディアクエリを利用する方法

Reactアプリケーションにおいて、メディアクエリを使ったテーマ切り替えを実現するためには、いくつかのアプローチがあります。ここでは、基本的な実装手順を紹介します。

ステップ1: メディアクエリの適用を計画する

まず、どのメディアクエリを利用するかを明確にします。テーマ切り替えの目的では、prefers-color-schemeを使うのが一般的です。このクエリは、ユーザーのデバイス設定に基づいてテーマモード(ダークまたはライト)を判定します。

ステップ2: window.matchMediaを使用する

JavaScriptのwindow.matchMediaメソッドを使って、指定したメディアクエリに一致するかどうかを確認できます。以下のコードは、Reactコンポーネント内でこの機能を使用する例です:

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

const useDarkMode = () => {
  const [isDarkMode, setIsDarkMode] = useState(
    window.matchMedia('(prefers-color-scheme: dark)').matches
  );

  useEffect(() => {
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    const handleChange = () => setIsDarkMode(mediaQuery.matches);

    mediaQuery.addEventListener('change', handleChange);
    return () => mediaQuery.removeEventListener('change', handleChange);
  }, []);

  return isDarkMode;
};

const App = () => {
  const isDarkMode = useDarkMode();

  return (
    <div style={{ backgroundColor: isDarkMode ? 'black' : 'white', color: isDarkMode ? 'white' : 'black' }}>
      <h1>{isDarkMode ? 'Dark Mode' : 'Light Mode'}</h1>
    </div>
  );
};

export default App;

ステップ3: スタイルの動的適用

上記の例では、isDarkModeの状態に応じてbackgroundColorcolorを動的に変更しています。ReactのuseStateuseEffectフックを活用することで、ユーザー設定の変更に応じてリアルタイムでUIを更新できます。

注意点

  1. 初期状態を考慮する:デフォルトのテーマを指定しておくと、設定が未指定のユーザーにも対応できます。
  2. イベントリスナーのクリーンアップ:メモリリークを防ぐために、useEffect内でリスナーを確実に解除してください。

ステップ4: カスタムフックとして再利用可能にする

useDarkModeのように、テーマ判定ロジックをカスタムフックとして切り出すことで、複数のコンポーネントで簡単に利用できるようになります。

このようにして、Reactアプリケーションでメディアクエリを利用し、ユーザー体験を向上させる動的なテーマ切り替えを実装することができます。次のセクションでは、これをさらに効率化するためのカスタムフックの詳細について説明します。

useMediaQueryフックの活用方法

Reactでメディアクエリを効率的に管理するには、再利用可能なカスタムフックを作成するのが効果的です。このフックを使用することで、複数のコンポーネントでメディアクエリを簡単に適用できます。

useMediaQueryフックの作成

以下のコードは、カスタムフックuseMediaQueryの実装例です:

import { useState, useEffect } from 'react';

const useMediaQuery = (query) => {
  const [matches, setMatches] = useState(window.matchMedia(query).matches);

  useEffect(() => {
    const mediaQueryList = window.matchMedia(query);
    const listener = (event) => setMatches(event.matches);

    mediaQueryList.addEventListener('change', listener);
    return () => mediaQueryList.removeEventListener('change', listener);
  }, [query]);

  return matches;
};

export default useMediaQuery;

このフックは、指定したメディアクエリが現在のデバイス条件に一致するかを判定します。

useMediaQueryフックの使用例

このフックを利用して、ダークモードかライトモードかを判定する例を示します。

import React from 'react';
import useMediaQuery from './useMediaQuery';

const App = () => {
  const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');

  return (
    <div style={{ backgroundColor: isDarkMode ? 'black' : 'white', color: isDarkMode ? 'white' : 'black' }}>
      <h1>{isDarkMode ? 'Dark Mode' : 'Light Mode'}</h1>
    </div>
  );
};

export default App;

この実装のポイント

  1. 簡潔さuseMediaQueryフックは単一のメディアクエリを判定するだけでなく、他のメディアクエリにも再利用可能です。
  2. リアルタイム更新:メディアクエリの状態が変更されると即座にUIが更新されます。
  3. モジュール化:ロジックをフックとして切り出すことで、コードの可読性とメンテナンス性が向上します。

複数のメディアクエリに対応する方法

複数の条件を同時に判定する場合、useMediaQueryを複数回使用できます。

const App = () => {
  const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
  const isLargeScreen = useMediaQuery('(min-width: 1024px)');

  return (
    <div>
      <h1>{isDarkMode ? 'Dark Mode' : 'Light Mode'}</h1>
      <h2>{isLargeScreen ? 'Large Screen' : 'Small Screen'}</h2>
    </div>
  );
};

この方法を活用すると、複雑なUIロジックも簡潔に記述できます。

デバッグと最適化

  • フックの挙動が正しいか確認するために、console.logを活用して状態を出力する。
  • 必要に応じて、クエリ文字列を定数や設定ファイルに抽出して管理する。

このようにuseMediaQueryフックを活用することで、Reactアプリケーションでのテーマ切り替えやレスポンシブ対応が簡単に行えるようになります。次のセクションでは、テーマの設計についてさらに掘り下げて説明します。

ダーク/ライトモードのテーマ設計

ダークモードとライトモードのテーマを実装するには、適切な設計が必要です。ここでは、Reactでテーマを構築するための設計方法と実装手順を解説します。

テーマ設計の基本方針

  1. 統一性のあるスタイル:テーマは一貫性を保つためにすべてのUIコンポーネントに適用されるべきです。
  2. カスタマイズ可能性:将来の拡張に備え、柔軟性のある設計を心がけます。
  3. グローバルなテーマ管理:React Contextを利用して、アプリ全体でテーマを共有します。

テーマオブジェクトの作成

まず、ダークモードとライトモード用のテーマオブジェクトを定義します。

const lightTheme = {
  background: '#ffffff',
  color: '#000000',
};

const darkTheme = {
  background: '#000000',
  color: '#ffffff',
};

export { lightTheme, darkTheme };

これらのオブジェクトには、各モードに必要なスタイル情報を定義します。

React Contextを使ったテーマ管理

テーマの切り替えを簡単にするために、Contextを利用してテーマ状態を管理します。

import React, { createContext, useContext, useState } from 'react';
import { lightTheme, darkTheme } from './themes';

const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState(lightTheme);

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === lightTheme ? darkTheme : lightTheme));
  };

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

export const useTheme = () => useContext(ThemeContext);

このThemeProviderをアプリケーションのルートに配置することで、どのコンポーネントからでもテーマにアクセスできるようになります。

テーマを適用する

テーマを使用してスタイルを動的に適用します。

import React from 'react';
import { useTheme } from './ThemeProvider';

const ThemedApp = () => {
  const { theme, toggleTheme } = useTheme();

  return (
    <div style={{ backgroundColor: theme.background, color: theme.color }}>
      <h1>React Theme Example</h1>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
};

export default ThemedApp;

このコードでは、現在のテーマに基づいてbackgroundColorcolorが適用され、ボタンでテーマを切り替えられるようになります。

CSS-in-JSの活用

複雑なスタイルを管理する場合、CSS-in-JSライブラリ(例:Styled-components、Emotion)を使用するのも有効です。

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import { useTheme } from './ThemeProvider';

const App = () => {
  const { theme } = useTheme();

  const styles = css`
    background-color: ${theme.background};
    color: ${theme.color};
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
  `;

  return <div css={styles}>Welcome to Themed App</div>;
};

ポイント

  1. 一元管理:テーマの色やスタイルを一か所にまとめることでメンテナンス性が向上します。
  2. 拡張性:将来的に追加テーマ(例:ハイコントラストモード)を導入しやすくなります。

次のセクションでは、テーマ管理の中でuseContextuseReducerを使用する方法について詳しく説明します。

useContextとuseReducerの応用

テーマ管理をより効率的に行うには、useContextuseReducerを組み合わせて状態管理を行う方法が効果的です。このアプローチにより、状態管理のロジックをシンプルかつ拡張可能に保つことができます。

useContextとuseReducerの基本的な役割

  • useContext:テーマをグローバルに共有し、どのコンポーネントでも利用可能にします。
  • useReducer:状態管理のロジックを1か所にまとめ、スケーラブルな設計を可能にします。

テーマ管理のためのReducerの実装

useReducerを利用してテーマ切り替えロジックを管理します。

const initialState = {
  theme: 'light', // 初期テーマ
};

const themeReducer = (state, action) => {
  switch (action.type) {
    case 'TOGGLE_THEME':
      return {
        ...state,
        theme: state.theme === 'light' ? 'dark' : 'light',
      };
    default:
      throw new Error(`Unhandled action type: ${action.type}`);
  }
};

このthemeReducerは、TOGGLE_THEMEアクションを受け取り、現在のテーマを切り替えます。

ThemeContextとProviderの作成

React Contextを使ってテーマの状態とアクションを共有します。

import React, { createContext, useReducer, useContext } from 'react';

const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [state, dispatch] = useReducer(themeReducer, initialState);

  const toggleTheme = () => {
    dispatch({ type: 'TOGGLE_THEME' });
  };

  const themeStyles = state.theme === 'light'
    ? { background: '#ffffff', color: '#000000' }
    : { background: '#000000', color: '#ffffff' };

  return (
    <ThemeContext.Provider value={{ theme: state.theme, toggleTheme, themeStyles }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => useContext(ThemeContext);

このコードにより、ThemeProviderをアプリのルートに配置するだけで、アプリ全体でテーマ情報を共有できます。

テーマの切り替えを実装

コンポーネント内でテーマを利用し、切り替えを行います。

import React from 'react';
import { useTheme } from './ThemeProvider';

const App = () => {
  const { theme, toggleTheme, themeStyles } = useTheme();

  return (
    <div style={{ ...themeStyles, height: '100vh', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
      <div>
        <h1>{theme === 'light' ? 'Light Mode' : 'Dark Mode'}</h1>
        <button onClick={toggleTheme}>Toggle Theme</button>
      </div>
    </div>
  );
};

export default App;

利点

  1. ロジックの明確化useReducerを利用することで、状態遷移のロジックが明確になります。
  2. 拡張性:新しいテーマやアクションを追加する際にコードを簡単に拡張できます。
  3. グローバルアクセスuseContextにより、状態をどのコンポーネントでも利用可能になります。

応用例: ユーザー設定の永続化

テーマ設定をローカルストレージに保存し、次回以降も利用できるようにするには、以下のようにします。

useEffect(() => {
  const savedTheme = localStorage.getItem('theme');
  if (savedTheme) {
    dispatch({ type: 'SET_THEME', payload: savedTheme });
  }
}, []);

useEffect(() => {
  localStorage.setItem('theme', state.theme);
}, [state.theme]);

このようにuseContextuseReducerを組み合わせることで、Reactアプリケーションで効率的なテーマ管理を実現できます。次のセクションでは、ユーザーのデバイス設定に基づく自動テーマ切り替えの方法を紹介します。

デバイスの設定を検知してテーマを切り替える

ユーザーのデバイス設定に基づいて自動的にテーマを切り替える機能を実装することで、よりシームレスでパーソナライズされたユーザー体験を提供できます。このセクションでは、prefers-color-schemeメディアクエリを活用した自動テーマ切り替えの方法を解説します。

メディアクエリを利用してデバイス設定を検知

デバイスのダークモード設定を取得するには、window.matchMediaを利用します。このAPIをReactコンポーネント内で使用する例を以下に示します。

import React, { useEffect, useReducer } from 'react';

const initialState = {
  theme: 'light', // 初期テーマ
};

const themeReducer = (state, action) => {
  switch (action.type) {
    case 'SET_THEME':
      return { ...state, theme: action.payload };
    default:
      return state;
  }
};

const useDeviceTheme = (dispatch) => {
  useEffect(() => {
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    const updateTheme = () => {
      const theme = mediaQuery.matches ? 'dark' : 'light';
      dispatch({ type: 'SET_THEME', payload: theme });
    };

    updateTheme(); // 初回に現在の設定を反映
    mediaQuery.addEventListener('change', updateTheme);

    return () => {
      mediaQuery.removeEventListener('change', updateTheme);
    };
  }, [dispatch]);
};

const App = () => {
  const [state, dispatch] = useReducer(themeReducer, initialState);

  useDeviceTheme(dispatch);

  const themeStyles =
    state.theme === 'dark'
      ? { background: '#000', color: '#fff' }
      : { background: '#fff', color: '#000' };

  return (
    <div style={{ ...themeStyles, height: '100vh', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
      <div>
        <h1>{state.theme === 'dark' ? 'Dark Mode' : 'Light Mode'}</h1>
      </div>
    </div>
  );
};

export default App;

この実装のポイント

  1. 初期設定の反映window.matchMedia('(prefers-color-scheme: dark)')を使って、アプリ起動時にユーザーのデバイス設定を反映します。
  2. リアルタイムの変更検知addEventListener('change', ...)を利用して設定変更を監視します。
  3. Reducerとの連携:状態管理をuseReducerで行い、アクションを通じてテーマを切り替えます。

ローカルストレージへの永続化

ユーザーが手動でテーマを切り替えた場合、設定をローカルストレージに保存することで、再度アプリを開いた際に反映させることが可能です。

useEffect(() => {
  const savedTheme = localStorage.getItem('theme');
  if (savedTheme) {
    dispatch({ type: 'SET_THEME', payload: savedTheme });
  } else {
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    const defaultTheme = mediaQuery.matches ? 'dark' : 'light';
    dispatch({ type: 'SET_THEME', payload: defaultTheme });
  }
}, []);

useEffect(() => {
  localStorage.setItem('theme', state.theme);
}, [state.theme]);

ユーザー選択とデバイス設定の共存

デバイス設定をベースにしつつ、ユーザーの選択を優先するために、次のようなロジックを実装します。

  1. 初回ロード時:ローカルストレージを確認し、保存されたテーマがあればそれを適用。
  2. 保存されたテーマがない場合:デバイス設定に基づくテーマを適用。
  3. 設定変更時:ユーザーが手動でテーマを切り替えた場合、ローカルストレージに保存。

このようにすることで、デバイス設定とユーザーの好みをバランス良く扱えます。

利点

  • ユーザー体験の向上:デバイスの設定に即したテーマが自動的に適用されます。
  • アクセシビリティ:設定変更の手間が不要で、直感的な操作が可能になります。
  • 柔軟性:手動テーマ切り替えと自動設定を組み合わせることで、多様なニーズに対応可能です。

次のセクションでは、メディアクエリとテーマ切り替えの実装におけるトラブルシューティングとデバッグ方法について詳しく解説します。

メディアクエリのデバッグとトラブルシューティング

メディアクエリを使ったテーマ切り替え機能をReactアプリに実装する際、思わぬ問題が発生することがあります。このセクションでは、よくある課題とその解決策、デバッグのためのツールや手法を紹介します。

よくある問題と解決策

1. メディアクエリが期待通りに動作しない

問題: prefers-color-schemeメディアクエリを使用してもテーマが正しく切り替わらない場合があります。

原因:

  • デバイスやブラウザがprefers-color-schemeに対応していない。
  • メディアクエリの書き方が誤っている。
  • 初期テーマが誤って設定されている。

解決策:

  • 最新のブラウザを使用する。
  • メディアクエリの記述を確認する。
  • デフォルトテーマを設定し、メディアクエリが適用されない場合でも動作するようにします。

例:

const isDarkModeSupported = window.matchMedia('(prefers-color-scheme)').media !== 'not all';
if (!isDarkModeSupported) {
  console.log('Prefers-color-scheme not supported on this device.');
}

2. テーマがリアルタイムで切り替わらない

問題: デバイスの設定を変更してもテーマが即時に更新されない。

原因:

  • イベントリスナーの登録が適切に行われていない。
  • 状態管理ロジックが適切に機能していない。

解決策:

  • addEventListenerを正しく登録し、useEffectでクリーンアップを行います。
useEffect(() => {
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
  const updateTheme = () => setTheme(mediaQuery.matches ? 'dark' : 'light');

  mediaQuery.addEventListener('change', updateTheme);
  updateTheme(); // 初期状態を設定
  return () => mediaQuery.removeEventListener('change', updateTheme);
}, []);

3. ローカルストレージとの競合

問題: ローカルストレージに保存されたテーマとデバイス設定が一致しない。

原因:

  • ローカルストレージのテーマ設定が上書きされていない。
  • デバイス設定が優先されているため、手動設定が無視される。

解決策:

  • ローカルストレージとデバイス設定を組み合わせたロジックを実装します。
useEffect(() => {
  const savedTheme = localStorage.getItem('theme');
  if (savedTheme) {
    setTheme(savedTheme);
  } else {
    const defaultTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    setTheme(defaultTheme);
  }
}, []);

デバッグのためのツールと手法

1. 開発者ツール

  • ブラウザの開発者ツールを使って、メディアクエリが正しく適用されているか確認します。
  • CSSセクションで@media (prefers-color-scheme: dark)が適用されているかを確認します。

2. JavaScriptコンソール

  • コンソールでwindow.matchMedia('(prefers-color-scheme: dark)').matchesの値を確認します。
console.log(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'Dark mode' : 'Light mode');

3. シミュレーション

  • 開発環境でダークモードとライトモードをシミュレートする。
  1. ブラウザのデベロッパーツールでダークモードを有効化。
  2. システム設定を変更してテスト。

パフォーマンスの最適化

  • 状態の不要な再計算を防ぐ:
    デバイス設定の変更頻度は少ないため、イベントリスナーの登録/解除を適切に管理します。
  • カスタムフックの再利用:
    メディアクエリロジックを一元化することで、コードを簡素化し、無駄な再描画を防ぎます。

まとめ

  • メディアクエリのトラブルシューティングでは、問題の特定と検証が鍵です。
  • ユーザー環境に依存する機能では、例外処理とフォールバックを用意しましょう。
  • 適切なツールとロジックを活用することで、Reactアプリケーションにおけるテーマ切り替えの信頼性が向上します。

次のセクションでは、実際にReactアプリでテーマ切り替えを実装する演習問題を提供します。

演習問題:Reactアプリでテーマ切り替えを実装

これまで学んだ内容を活用し、Reactアプリケーションでテーマ切り替え機能を実装する課題に挑戦しましょう。この演習を通じて、ダークモードとライトモードのテーマ切り替え機能を完成させるスキルを実践的に習得します。


課題概要

Reactで以下の機能を持つアプリケーションを作成してください:

  1. ダークモードとライトモードを手動で切り替えるボタンを設置。
  2. ユーザーのデバイス設定(prefers-color-scheme)に応じて初期テーマを適用。
  3. ユーザーが手動で選択したテーマをローカルストレージに保存し、再度訪問時に選択内容を保持。
  4. カスタムフックとContext APIを使用してテーマを管理。

完成イメージ

  • 初回アクセス時にデバイス設定(ダークモードまたはライトモード)に基づいてテーマが適用される。
  • ユーザーがテーマを切り替えると、即時にUIが更新され、選択内容が保存される。
  • 他のコンポーネントでもテーマ情報が利用可能。

実装のヒント

ステップ1: テーマオブジェクトの定義

テーマ用のスタイルオブジェクトを作成します。

const lightTheme = {
  background: '#ffffff',
  color: '#000000',
};

const darkTheme = {
  background: '#000000',
  color: '#ffffff',
};

ステップ2: カスタムフックの作成

useThemeフックを作成し、メディアクエリとローカルストレージを活用してテーマを管理します。

ステップ3: Context APIでテーマを共有

Contextを使って、アプリ全体でテーマを利用できるようにします。

ステップ4: テーマ切り替えの実装

ボタンを追加してテーマを切り替える機能を実装します。


演習コード例

以下のコードを参考に、アプリケーションを完成させてください。

import React, { createContext, useContext, useEffect, useState } from 'react';

const ThemeContext = createContext();

const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');

  useEffect(() => {
    const savedTheme = localStorage.getItem('theme');
    if (savedTheme) {
      setTheme(savedTheme);
    } else {
      const defaultTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
      setTheme(defaultTheme);
    }
  }, []);

  useEffect(() => {
    localStorage.setItem('theme', theme);
  }, [theme]);

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

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

const useTheme = () => useContext(ThemeContext);

const App = () => {
  const { theme, toggleTheme } = useTheme();

  const themeStyles = theme === 'dark'
    ? { backgroundColor: '#000', color: '#fff' }
    : { backgroundColor: '#fff', color: '#000' };

  return (
    <div style={{ ...themeStyles, height: '100vh', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
      <div>
        <h1>{theme === 'dark' ? 'Dark Mode' : 'Light Mode'}</h1>
        <button onClick={toggleTheme}>Toggle Theme</button>
      </div>
    </div>
  );
};

export default function Root() {
  return (
    <ThemeProvider>
      <App />
    </ThemeProvider>
  );
}

課題のチェックポイント

  1. 初回ロード時にデバイス設定が適用されているか。
  2. テーマを切り替えた際に即座に反映されるか。
  3. ローカルストレージにテーマ設定が保存され、再訪問時に反映されているか。

応用課題

  1. アニメーションを追加してテーマ切り替えをよりスムーズにする。
  2. 複数のテーマ(例:ブルーモード、ハイコントラストモードなど)をサポートする。
  3. テーマ設定を設定ページやモーダルで管理できるようにする。

次のセクションでは、記事全体を振り返り、学んだ内容を簡潔にまとめます。

まとめ

本記事では、Reactアプリケーションにおけるメディアクエリを活用したダーク/ライトモードのテーマ切り替え方法を詳しく解説しました。メディアクエリの基本的な仕組みから始まり、useMediaQueryやContext API、useReducerを活用した効率的なテーマ管理の方法を紹介しました。さらに、デバイスの設定を検知してテーマを自動的に切り替える方法や、トラブルシューティング、演習問題を通じて実装スキルを深めることができました。

ダークモードとライトモードは、視覚的な快適さとアクセシビリティを向上させるだけでなく、ユーザー体験を大きく改善します。Reactでこれを実現するには、メディアクエリやローカルストレージなどの仕組みを効果的に利用することが重要です。これらの知識を応用し、魅力的で機能的なテーマ切り替えを持つアプリケーションを構築してください。

コメント

コメントする

目次