11日目: React hooks の useContext を探訪

React の状態管理において、state のバケツリレーをするのは実は最も単純ではあるが、親から子に伝播するルールだと、メンテナンスが大変になる。

そのあたりは以下の記事で考え方が整理されていた。

weseek.co.jp

それぞれの良し悪しはあるにせよ、それぞれ素振りしていく必要があると思い、手始めに React Context を使ってみることに。

いつものように npm create vite@latest で React + TypeScript のプロジェクトを作成。

概ね記事のトレースのコードになるが、Top・Middle・Bottom と構成して、Bottom から状態を参照するようにしてみた。

import { useState, createContext, useContext } from 'react'
import './App.css'

type SampleContextType = {
  color: string;
  setColor: (color: string) => void;
}

const defaultSampleContext: SampleContextType = {
  color: 'red',
  setColor: () => {},
}

const SampleContext = createContext<SampleContextType>(defaultSampleContext)

const Top: React.FC = () => {
  const [color, setColor] = useState('blue')

  return (
    <div>
      <h1>Top</h1>
      <SampleContext.Provider value={{ color, setColor }}>
        <Middle />
      </SampleContext.Provider>
    </div>
  )
}

const Middle: React.FC = () => {
  return (
    <div>
      <h2>Middle</h2>
      <Bottom />
    </div>
  )
}

const Bottom: React.FC = () => {
  const { color, setColor } = useContext(SampleContext)

  return (
    <div>
      <h3>Bottom</h3>
      <p style={{ color }}>Hello World!</p>
      <button onClick={() => setColor('red')}>Red</button>
      <button onClick={() => setColor('blue')}>Blue</button>
      <button onClick={() => setColor('green')}>Green</button>
      <button onClick={() => setColor('yellow')}>Yellow</button>
    </div>
  )
}

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

  return (
    <>
      <Top />
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
      </div>
    </>
  )
}

export default App
  1. createContext でコンテキストを作成
  2. useContext でコンテキストを参照
  3. Provider でコンテキストを提供

というシンプルな流れで、状態を参照することができる。

とはいえ、1つのコンテキストを用意して、そこに全部を詰め込むのではなく、複数のコンテキストを用意するのがよさそうではある。

ライブラリを追加してインストールする必要がないので、小規模であればこれで十分かもしれない。

React の公式ガイドもあるので目を通してみた。いつも「バケツリレー」と呼んでいる、Props の伝播のことを「Prop Drilling」と呼んでいた。

コンテクストを使う前に、のセクションがなかなか興味深い。

ja.reactjs.org

  1. まずは props を渡す方法から始めましょう。
  2. コンポーネントを抽出して、children を JSX として渡す方法を検討しましょう。

確かに、children を渡せるようにすると、中間コンポーネントの経由がグッと減ってよい。

グローバルな状態管理を使うことを前提にせず、コンポーネント抽出の設計をすっきりさせることを優先してもいいのかも。

ググったりライブラリをいろいろ試すよりもまず初手では React の公式ドキュメントの「state の管理」を読むのを優先したほうがいいことに気づいた。

ja.react.dev