React学習記録 useContext
useContextを使用することでグローバルな状態を作成し、コンポーネントツリーのどこからでもコンテキストの値を簡単に取得できる。通常、親コンポーネントから子コンポーネントへpropsを渡す必要があるが、useContextを使うことで、深い階層のコンポーネントにも直接データを提供できる。これにより、props を何階層も渡す 「props drilling」所謂バケツリレーを避けられる。
useContext の基本概念
Context API:React の組み込み機能で、アプリケーション内でデータを グローバルに共有 するための仕組み。
useContext:コンポーネント内で、Context で提供されたデータにアクセスするためのフック。
使用例 (モードの切り替え機能)
フォルダ構成()
/src
├── components
│ ├── Parent.jsx
│ ├── Child.jsx
│ ├── GrandChild.jsx
├── context
│ ├── ThemeContext.jsx ← Context を定義
├── App.jsx
1:ThemeContext.jsx
import { createContext, useContext, useState } from "react";
// Context を作成
const ThemeContext = createContext();
// Provider コンポーネントを作成
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = () => {
setTheme(theme === "light" ? "dark" : "light");
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
2:App.jsx
import { ThemeProvider } from "./context/ThemeContext";
import Parent from "./components/Parent";
function App() {
return (
<ThemeProvider>
<Parent /> //親コンポーネント呼び出し
</ThemeProvider>
);
}
export default App;
3:Parent.jsx
import Child from "./Child";
function Parent() {
return <Child/>; //子コンポーネント呼び出し
}
export default Parent;
4:Child.jsx
import GrandChild from "./GrandChild";
function Child() {
return <GrandChild/>; //孫コンポーネント呼び出し
}
export default Child;
5:GrandChild.jsx
import { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
function GrandChild() {
// useContext で直接テーマと切り替え関数を取得
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div style={{ background: theme === "light" ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff", padding: "20px" }}>
<p>現在のテーマ: {theme}</p>
<button onClick={toggleTheme}>テーマを切り替え</button>
</div>
);
}
export default GrandChild;
上記コードでは、親コンポーネントである Parent.jsx からpropsのバケツリレーを行わずに孫コンポーネントの GrandChild.jsx でContextにアクセスすることができ、テーマの変更処理を行うことができる。使用しなかった場合は以下のようになると考えられる。
1:App.jsx (useContext不使用)
import { useState } from "react";
import Parent from "./components/Parent";
function App() {
const [theme, setTheme] = useState("light");
const toggleTheme = () => {
setTheme(theme === "light" ? "dark" : "light");
};
return (
<Parent theme={theme} toggleTheme={toggleTheme} />
);
}
export default App;
2:Parent.jsx (useContext不使用)
import Child from "./Child";
function Parent({ theme, toggleTheme }) {
return <Child theme={theme} toggleTheme={toggleTheme} />;
}
export default Parent;
3:Child.jsx (useContext不使用)
import GrandChild from "./GrandChild";
function Child({ theme, toggleTheme }) {
return <GrandChild theme={theme} toggleTheme={toggleTheme} />;
}
export default Child;
4:GrandChild.jsx (useContext不使用)
function GrandChild({ theme, toggleTheme }) {
return (
<div style={{ background: theme === "light" ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff", padding: "20px" }}>
<p>現在のテーマ: {theme}</p>
<button onClick={toggleTheme}>テーマを切り替え</button>
</div>
);
}
export default GrandChild;
useContext を使用せずに、props を使ってテーマの状態を親コンポーネントから子・孫コンポーネントに伝播しているが、コンポーネント間でのデータの受け渡しが煩雑になる。
このようにuseContextを使用することでコンポーネントの管理がしやすく、シンプルで効率的な状態共有が可能となる。
アプリケーション全体で共通の情報(テーマや認証情報など)を管理する場合に非常に有効。
補足
Context に渡すデータが変化すると、そのデータを利用しているすべてのコンポーネントが再レンダリングされるため、頻繁に変更されるデータを Context に渡すとパフォーマンスの問題が発生する可能性があるため注意