useContextで使う

箱から取り出す

前の回で作った ThemeContext は、まだ誰も覗いていません。覗くのが useContext です。

import { useContext } from "react"; import { ThemeContext } from "./ThemeContext"; function PriceTag({ price }: PriceTagProps) { const theme = useContext(ThemeContext); return <p className={"price " + theme}>{price}</p>; }

useContext(ThemeContext) は、自分より上にあるいちばん近い Provider の value を返します。PriceTag が何段深くても、間に何があっても関係ありません。props を1つも受け取らずに theme が手に入ります。

戻り値の型は、箱を作るときに書いた <Theme> から決まります。ここで theme.toUpperCase() のような打ち間違いをすれば、その場で止まります。

バケツリレーを消す

取り出せるようになったので、途中の受け渡しは要らなくなります。

  • ItemListProps から theme を消す
  • ItemCardProps から theme を消す
  • 呼び出しの theme={theme} を消す

ItemList と ItemCard が、商品を並べるという本来の仕事だけを持つ形に戻ります。使う人が直接取りに行くので、通り道になる部品がいなくなるわけです。

Provider が無いとどうなるか

useContext は、上に Provider が見つからないと既定値を返します。作るときに書いた "light" です。

エラーにならないので気付きにくいのが厄介なところです。「切り替えても何も変わらない」という不具合の多くは、Provider の外側で useContext を呼んでいるのが原因です。既定値は、そういうときの目印になる値にしておくと助かります。

使いどころ

Context は便利ですが、何でも入れる置き場ではありません。テーマ、ログイン中のユーザー、言語のように、アプリのあちこちで同じものを見たい少数のものに向いています。1つの画面の中だけで使う値は、これまでどおり props で足ります。

演習

PriceTag が useContext でテーマを取り、途中の受け渡しを消します。

ヒント

App.tsx
ThemeContext.tsx
App.tsx
ThemeContext.tsx
プレビュー

できているか

  • カードが3枚並んでいる
  • 3枚とも Context からテーマが届いている
  • 価格が 円 付きで出ている