バケツリレーの限界
深いところまで届けるということ
fleama の画面を暗くする「ダークモード」を付けることになりました。暗いかどうかは画面全体の話なので、いちばん外側で決めます。ところが、実際に色を変えたいのは価格の文字のようないちばん奥の部品です。
いまの fleama は、外側から順に App、ItemList、ItemCard、PriceTag と4段になっています。テーマを App で決めて PriceTag で使うには、間の ItemList と ItemCard にも渡してもらうしかありません。
TypeScript (JSX)
<ItemList items={items} theme={theme} />ItemList は受け取った theme を自分では使わず、そのまま ItemCard に渡します。ItemCard も使わず PriceTag に渡します。バケツリレーと呼ばれる形です。
何が辛いのか
動くには動きます。辛いのは、増えたときと変わったときです。
- 途中の部品が theme を使っていないのに、props の型に theme を書かされる
- 段が5段10段と深くなると、渡し忘れた1か所を探すのに時間が溶ける
- あとで「文字サイズ」も共有したくなると、また全段に足すことになる
- ItemList を別の場所で使い回そうとすると、要らない theme まで渡す羽目になる
つまり、途中の部品が「通り道」にされてしまうのが問題です。ItemList の仕事は商品を並べることであって、テーマを運ぶことではありません。
それでも一度は書いてみる
いきなり便利な仕組みから入ると、何が便利なのか分かりません。この回では、あえて4段のバケツリレーを自分の手で書きます。次の回から、この受け渡しを1本ずつ消していきます。
型は "light" | "dark" のユニオンにしておきます。文字列のままにすると "Dark" のような表記ゆれが通ってしまうためです。
次の回の準備として Context を知る
Context は、途中の props を通さずに値を配るための入れ物です。たとえば表示言語の箱は、部品の外で1回だけ作ります。
TypeScript (JSX)
import { createContext } from "react";
type Language = "ja" | "en";
const LanguageContext = createContext<Language>("ja");山かっこの型は入れられる値の型、丸かっこの値は Provider が無いときの既定値です。Provider は値を配る範囲を決めます。
TypeScript (JSX)
<LanguageContext.Provider value="en">
<HelpLink />
</LanguageContext.Provider>value は包んだ内側の部品だけに届きます。外側には届きません。この回は props の受け渡しを確かめ、次の回でテーマの Context と Provider を自分で書きます。
演習
テーマを App から PriceTag まで、props で運びます。