Provider 化の判断基準 — 消費者が 1 つなら Context にする意味がない
問題
useAppView を Provider + Context 化したが、実際に useAppView() を呼ぶのは
AppShellBody 1 コンポーネントだけだった。
// Provider を挟んだが、消費者は Body 1 つだけ
<AppViewProvider>
<AppShellBody /> {/* ← ここでしか useAppView() を呼ばない */}
</AppViewProvider>
原因
Context は「複数の離れた子孫で state を共有する」ための仕組み。
消費者が 1 つしかないなら、props で直接渡すか、その state を親コンポーネント内で
useState で持つだけで十分。
不要な Context 化は次のような二次的な複雑性を生む。
- Provider の配置問題(どの高さに置くか、
valueの memo 化など)。 - key remount の副作用(Provider に
keyを付けて state リセットすると配下の in-flight 通知が飛ぶ)。 - Body 分離(Provider の下に消費用の Body を切り出す不自然な分割)。
これらは「消費者が複数いる」状況では割に合うが、消費者が 1 つなら得が無いコストでしかない。
解決
- Provider は App 直下に hoist(配置問題を消す)、切り出していた Body は撤去。
- 消費者が 1 つなら Context をやめ、
useState+ props で足りる。
// 消費者が 1 つなら Context 不要。親で state を持って渡すだけ
function App() {
const view = useAppView(); // ただの hook / state
return <AppShellBody view={view} />;
}
今後の前提条件
Context 化する前に「消費者が本当に複数いるか」を確認する。1 つなら Context にしない。
関連: 「Context を使う前に検討すること(コンポジション優先)」「Provider key remount での state リセットは anti-pattern」
まとめ
- Context は「複数の離れた子孫で共有する」ための道具。消費者 1 つでは意味が無い。
- 消費者が 1 つなら props / 親の
useStateで十分。Context は Provider 配置・key remount・Body 分離という二次コストを増やすだけ。 - Context 化の前提条件は「消費者が複数いること」。ここを最初に確認する。