React Contextとは?
React Contextは、コンポーネント間で共有したいデータを効率的に管理・提供する仕組みです。通常、データはprops
を使って親コンポーネントから子コンポーネントへ手渡しで渡します。しかし、ツリー構造が複雑になると、データを渡すために中間のコンポーネントにもプロップスを渡さなければならない「プロップスドリリング」という問題が発生します。
Context
を使うと、親から子へ直接データを渡す必要がなくなり、どのコンポーネントからでもそのデータへアクセスできるようになります。データの共有がシンプルになり、コードがわかりやすくなるのです。なお、Context
は、props
とは別の方法でコンポーネントに動的に値を渡す、React純正のAPIです。
useContextとは?
React Hooksの1つで、グローバルにデータを管理することができる仕組みです。コンポーネント間のデータ共有を簡単にします。
例えば、
テーマの切り替え
ライトモード、ダークモードなど使用するテーマを管理するために、Context
を使用できます。コンポーネント内でテーマを設定する代わりに、テーマ情報をContext
に保存し、アプリ全体で使用できるようにします。
言語設定の切り替え
多言語をサポートする場合、言語設定をContext
に保存し、アプリ内の複数のコンポーネントで共有できます。
グローバルな状態の管理
アプリ全体で使用する設定やデータをグローバルに管理するためContext
を使用することができます。共有するAPIキー、データベースの接続情報、ユーザーのお気に入りアイテムなどです。
※必ずしも全ての状態をグローバルに管理する必要は無く、またuseContext
でなくとも同じような実装ができる機能はあるので、事前に必要な状態を考え、適切に設計することが重要とのことです。経験値から判断できるようになるのではないかと思ってます。
基本的な記述
// createContextをインポート
import React, { createContext } from 'react';
// createContext()を使用し、コンテキストの定義
// 引数には、propsを通さずに渡したい値を記述
export const TestContext = createContext("useContextの使い方");
// 定義したcontext(TestContext)のProviderというコンポーネントで
// stateを使用するコンポーネントを囲います
// valueにセットされた値がuseContextを通して
// ネストされたコンポーネントで取得することができるようになる
<TestContext.Provider value={[value, setValue]}>
<Child />
</TestContext.Provider>
// useContextをインポート
import { useContext } from "react";
// value = useContextの使い方
const value = useContext(TestContext);
使用例 (テーマの切り替え)
codesandboxなどでサクッと試せる内容です。
以下のファイルを作成します。
src
├ App.jsx
├ ThemedButton.jsx
┗ ThemeProvider.jsx
import "./styles.css";
import { ThemeProvider } from "./ThemeProvider";
import ThemedButton from "./ThemedButton";
export default function App() {
return (
<ThemeProvider>
<div style={{ textAlign: "center", marginTop: "50px" }}>
<h1>テーマの切り替え</h1>
<ThemedButton />
</div>
</ThemeProvider>
);
}
import React, { createContext, useState } from "react";
// ThemeContextを作成
const ThemeContext = createContext();
// ThemeProviderコンポーネントを作成
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light"); // 初期テーマは 'light'
// テーマを切り替え
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
// Providerコンポーネントで包むことによって、Provider配下のコンテキストを決定する
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export { ThemeContext, ThemeProvider };
import React, { useContext } from "react";
import { ThemeContext } from "./ThemeProvider";
function ThemedButton() {
// useContext でコンテキストからテーマとテーマを切り替える関数を取得
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button
onClick={toggleTheme}
style={{
backgroundColor: theme === "light" ? "#fff" : "#333",
color: theme === "light" ? "#000" : "#fff",
padding: "10px 20px",
border: "none",
borderRadius: "5px",
}}
>
テーマ : {theme} {/*light, dark*/}
</button>
);
}
export default ThemedButton;