◆ デフォルト値がデフォルト値じゃなかった
◆ Provider の value を指定しないと その内側は undefined
◆ Provider の外側は createContext のデフォルト値
◆ Provider をレンダリングするコンポーネントはその Provider の外側になる

React を使わず WebComponents で作ってると Context ぽいグローバルにどのコンポーネントからでもデータを取得できる仕組みは積極的に使ってたのですが React だと他でも使い回せるコンポーネントが作りやすかったり Context が結構面倒でほとんどつかってませんでした

ですが 一部ライブラリを入れると props を子に渡す仕組みが提供されず 「やりたいなら Context を使って」 みたいなのもあります
仕方なく Context を使ったのですが デフォルト値で苦戦しました

今回は Preact+htm じゃなくて React+JSX になってます

useContext の結果が undefined になる

const TestContext = React.createContext("DEFAULT")

const Component1 = () => {
const value = useContext(TestContext)
console.log("component1", value)

return (
<div>
{value}
</div>
)
}

const App = () => {
const value = useContext(TestContext)
console.log("app", value)

return (
<TestContext.Provider>
<div>
<h1>Test Page</h1>
<Component1 />
</div>
</TestContext.Provider>
)
}

App と Component1 のそれぞれで useContext して TestContext のデータを取得しています
createContext で "DEFAULT" を指定したのでどっちもそれになることを期待したのですが

app DEFAULT
component1 undefined

結果が違っていて component1 は undefined です

Context の使い方が間違ってるのかなとあれこれ調べたのに関数コンポーネントだと Consumer とかは要らずに useContext だけで良いみたいです
これにかなーり困らせられたわけですが 原因は単純に Provider に value を渡してないことでした

渡してないんだから デフォルト値の "DEFAULT" じゃないの? と思うのですがこれは Provider の外側で使った場合の値のようです
App コンポーネントでは Provider を使ってはいますが このコンポーネントがレンダリングする部分であって App 自体は含まれません
Provider の中のツリーの Component1 が Provider の対象になります
Provider に value を指定すると無事 Component1 内の TestContext の値が value で指定したものになりました

ドキュメントの例が不親切

下の方の API までよく読めば書いてはいるのですが 上の方の例がデフォルト値と違う値を入れる場合だけなんですよね
それだと 違うから設定してるのであって デフォルト値でいいなら指定不要なんだなって思うのは仕方ないと思います
createContext に設定するものを「デフォルト値」と呼んでるのですから

みんな通りそうな罠だと思うのに StackOverflow で useContext が undefined になるとかググってもそれらしい回答が見当たらなくて更に困りました

デフォルト値を作る場所

createContext でデフォルト値を指定してもそれを使ってくれないなら Provider をレンダリングするコンポーネントのところで初期値を作れば良いように思います
createContext では引数を指定しません

Context を使うところでその Context の値を更新できるように Context 自体に Context の更新をする関数を持たせるのなら 結局 Provider の value へ渡す値を Provider を使うコンポーネントの state へ入れて setter 関数を作って それを Context のオブジェクトに含めるという処理が入ります
Provider を使うところで value を色々変更するのなら createContext よりも Provier を使うコンポーネントで初期値を作ったほうが良いように思います

createContext のところで初期値を作るメリットは localStorage みたいな外部から初期データを読み込む場合に コンポーネント内でそれをしたくない時くらいでしょうか

コンポーネント外のグローバルなところで

export const FooContext = React.createContext(localStorage.foo)

としておいて Provider を作るコンポーネントで

const foo = useContext(FooContext)

のように createContext で作った初期値を受け取って

return (
<FooContext.Provider value={foo}>...</FooContext.Provider>
)

そのまま Provider の value にします