本文へスキップ
BecomeCoder

Reactコース · 第5章 状態の共有と再利用 · レッスン15

useContextでバケツリレーを解消する

ブラウザで完結

導入

「テーマ(ダーク/ライト)」や「ログイン中のユーザー」のように、アプリの広い範囲で使いたい値があります。これを props だけで配ろうとすると、途中の部品は使いもしないのに次へ渡すためだけに props を受け取ることになります。これが props のバケツリレーです。useContext を使うと、途中を経由せずに必要なコンポーネントへ直接値を届けられます。

説明

React.createContext(初期値) で「入れ物」を作り、上位で <Context.Provider value={...}> に包み、下位のどこからでも React.useContext(Context) で読み取ります。

flowchart TB
  provider["ThemeContext.Provider<br/>value: theme"]
  toolbar["Toolbar<br/>(themeを中継しない)"]
  button["ThemedButton<br/>useContext(ThemeContext)で直接取得"]
  provider --> toolbar
  toolbar --> button
  provider -.->|"Contextで直接届く(propsのバケツリレー不要)"| button
const ThemeContext = React.createContext("light");

function App() {
  const [theme, setTheme] = React.useState("light");
  return (
    <ThemeContext.Provider value={theme}>
      <div style={{ fontFamily: "system-ui" }}>
        <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
          テーマ切り替え(現在: {theme}
        </button>
        <Toolbar />
      </div>
    </ThemeContext.Provider>
  );
}

// Toolbar は theme をまったく使わないので、受け取りも中継もしない
function Toolbar() {
  return (
    <div style={{ padding: 12, border: "1px dashed #94a3b8", marginTop: 8 }}>
      <ThemedButton />
    </div>
  );
}

// ThemedButton は2階層下にいるが、useContext で直接 theme を受け取れる
function ThemedButton() {
  const theme = React.useContext(ThemeContext);
  return (
    <button
      style={{
        background: theme === "light" ? "#f1f5f9" : "#1e293b",
        color: theme === "light" ? "#0f172a" : "#f8fafc",
        border: "1px solid #94a3b8",
        padding: "6px 12px",
      }}
    >
      いまのテーマ: {theme}
    </button>
  );
}
  • React.createContext("light") … 入れ物(Context)を作ります。引数は「Provider に包まれなかったときのデフォルト値」です。
  • <ThemeContext.Provider value={theme}> … このタグの内側すべてに theme を配ります。
  • React.useContext(ThemeContext) … 一番近い Provider の value を取り出します。Toolbartheme を props として受け取っていない点に注目してください。
  • Provider の value が変わると、useContext で読んでいるコンポーネントは自動で再描画されます。

やってみよう

Toolbar の中に、もう1つ別の場所で React.useContext(ThemeContext) を使う ThemedText コンポーネント(<p> でテーマ名を表示するだけ)を作って置いてみましょう。AppToolbar を1文字も変えずに、新しい部品がテーマを受け取れることを確かめてください。

実際に動かしてみよう

下のエディタにReactのコードを書くと、右側のプレビューにその場で描画されます。`function App() { ... }` を定義すると自動で表示されます(React・useState などは React.useState の形で使えます)。本文の例を打ち込んだり書き換えたりして、表示の変化を確かめながら進めましょう。

React — ブラウザ内で実行

JSXをその場で変換して描画する学習用React環境(React18 + Babel・同梱)を読み込みます。
スクロールして表示された時点でも自動で読み込まれます。