KAKUTA TECH BLOG

Blog Article

useContext とは何か?「 グローバルな状態共有 」の意味

はじめに

React でアプリを作っていると、「 この値、いろいろなコンポーネントで使いたい 」という場面に必ず出てきます。ログインユーザーの情報、テーマカラー、言語設定など、画面のあちこちで必要になるデータです。

React は本来、親から子へ props を使って値を渡す仕組みです。しかし、コンポーネントの階層が深くなると、関係のないコンポーネントを何段階も通して値を渡すことになり、コードの見通しが悪くなります。これがいわゆる「 props のバケツリレー 」です。

この問題を解決するための仕組みが useContext です。useContext を理解すると、「 グローバルな状態共有 」という言葉の本当の意味が見えてきます。この記事では、その正体を初学者にもわかるように丁寧に解説します。

参考にしたリンク

https://react.dev/reference/react/useContext

https://react.dev/learn/passing-data-deeply-with-context

“Context lets the parent component make some information available to any component in the tree below it—no matter how deep—without passing it explicitly through props.”

出典:https://react.dev/learn/passing-data-deeply-with-context

useContext とは何か

useContext を一言で言うなら、 props を使わずに、ツリー全体へ値を配布する仕組み です。

React の「 親から子へ 」というデータの流れを壊さずに、深い階層へ値を届けるための公式な方法です。

例えば、ログインユーザーの情報をヘッダー、サイドバー、メイン画面で使いたい場合を考えます。これらのコンポーネントがツリーの離れた場所にあると、共通の親から何段階も props を渡す必要があります。

中間コンポーネントはその値を使わないのに、ただ渡すだけの役割を持つことになり、責務が曖昧になります。構造が複雑になり、修正や保守が難しくなります。

いつ useContext を使うべきか

  • テーマカラー
  • 言語設定
  • ログインユーザー情報

など、アプリ全体で共通して使う値に適しています。特定の親子関係に依存せず、どこからでも必要になる値です。

Context とは何か

Context は、React が提供する「 値の共有箱 」です。特定の値を Context に入れておくと、その配下にあるどのコンポーネントからでも取り出せます。

const UserContext = createContext(null)
<UserContext.Provider value={user}>
  <App />
</UserContext.Provider>

これで、App 以下のどのコンポーネントからでも user を取得できます。

グローバルな状態共有とはどういう意味か

ここでの「 グローバル 」とは、JavaScript のグローバル変数ではありません。Provider に囲まれた React ツリーの範囲で、どこからでもアクセスできるという意味です。React の管理下にある、安全な共有領域です。

【よくある勘違い】useContext は state を管理していない

非常に多い勘違いがあります。それは「 useContext は state 管理の仕組みである 」という誤解です。

実は、 useContext は state を管理していません。state を運ぶ仕組みなだけです。

次のコードを見てください。

const CounterContext = createContext(null)

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

  return (
    <CounterContext.Provider value={{ count, setCount }}>
      <Counter />
    </CounterContext.Provider>
  )
}

function Counter() {
  const { count, setCount } = useContext(CounterContext)

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  )
}

この例で、count を管理しているのは useState です。useContext は、その countsetCount を「 運んでいる 」だけです。

つまり、

  • 状態を作るのは useState
  • 状態を配るのが useContext

という役割分担になっています。

state と useContext の役割の違い

項目

useState

useContext

役割

状態を作る

状態を配る

管理

ローカル

広範囲共有

単体で state 管理

できる

できない

useContext を使ったグローバルステート管理方法

1. Context を作成する

まずは、共有するための箱を作ります。

import { createContext } from "react"

export const CounterContext = createContext(null)

2. state を作成する

次に、実際に管理したい state を useState で作ります。

import { useState } from "react"

const [count, setCount] = useState(0)

3. Provider で state を配布する

作成した state を Providervalue に入れて、ツリー全体へ配布します。

<CounterContext.Provider value={{ count, setCount }}>
  <App />
</CounterContext.Provider>

4. useContext で受け取る

どの階層のコンポーネントからでも、次のように受け取れます。props は不要です。

import { useContext } from "react"
import { CounterContext } from "./CounterContext"

const { count, setCount } = useContext(CounterContext)

この 4 手順で、props を使わずにグローバルな state 共有が実現できます。

Zustand とは何か

Zustand (ツー・スタンド)は、React 向けの軽量な状態管理ライブラリです。ドイツ語で「状態(state)」という意味です。

useContext と違い、state の作成、更新、共有を 1 つの仕組みでまとめて扱えます。

useContext では useState と組み合わせる必要がありましたが、Zustand ではストアと呼ばれる場所に state を定義し、どのコンポーネントからでも直接参照と更新ができます。

大きな特徴は、Context を使わなくてもグローバルな state を扱える点です。

じゃあ全部 Zustand で良くない?

一見そう思えますが、必ずしもそうではありません。

useContext は React 標準の仕組みであり、小規模から中規模のアプリで「 値を広く共有したい 」だけの場合には十分です。依存ライブラリも増えません。

一方で、状態が増えてきたり、更新ロジックが複雑になったり、パフォーマンスの最適化が必要になったりすると、Zustand のようなライブラリが力を発揮します。

つまり、

  • 単純な共有 → useContext
  • 複雑な状態管理 → Zustand

という使い分けが重要です。

具体例で整理する

useContext が適しているケース

  • テーマカラー
  • 言語設定
  • ログインユーザー情報

Zustand が適しているケース

  • 多数の state を扱う
  • 更新ロジックが複雑
  • パフォーマンスを意識する必要がある

まとめ

useContext は、props を使わずにコンポーネントツリー全体へ値を配布する仕組みです。しかし、state を管理する仕組みではありません。state を運ぶための通路です。

ポイント整理

  • props のバケツリレーを防ぐ
  • アプリ全体で共通の値を扱える
  • state を管理しているのは useState
  • 複雑になったら Zustand の出番

この違いを理解すると、React の設計が一気にクリアになります。