クイック解決策
このクラッシュは、useContextを呼び出しているコンポーネントが <MyContext.Provider> ツリーの外側にあるために発生します。Reactは上方向に向かって Provider を探し、見つからない場合はデフォルト値を返します。この値は多くの場合 undefined です。これを修正するには、useContext の呼び出しを子コンポーネントに移動するか、エントリーポイント(main.jsx や _app.js など)を Provider でラップしてください。
// ❌ 悪い例: コンポーネントが Provider と兄弟関係にある
function App() {
return (
<>
<UserProvider>
<Header />
</UserProvider>
<UserProfile /> // エラー!UserProfile はツリーの外側にあります
</>
);
}
// ✅ 良い例: コンポーネントが Provider の内部にネストされている
function App() {
return (
<UserProvider>
<Header />
<UserProfile /> // 正常に動作します
</UserProvider>
);
}
なぜこのエラーが発生するのか
引数を渡さずに const UserContext = createContext(); を実行すると、React はデフォルト値を undefined に設定します。その後、まだ「提供(provide)」されていないコンテキストから { user } を分割代入しようとすると、実質的に { user } = undefined を実行しようとしていることになります。JavaScript では、何もないところからプロパティを取り出すことはできないため、即座に TypeError がスローされます。
コンテキストをラジオの信号のように考えてみてください。コンポーネントが放送範囲(Provider)内にいなければ、ノイズしか聞こえません。
よくある落とし穴と解決策
1. Provider を定義しているのと同じコンポーネントでコンテキストを使用している
React 開発者は、Provider をレンダリングしているのと同じファイル内で useContext を使おうとすることがよくあります。これは必ず失敗します。Provider はその**子孫(descendants)**に対してのみ放送を行い、自分自身には放送しないからです。
// このコンポーネントは自分自身のコンテキストを見つけることができません
export default function Dashboard() {
const { user } = useContext(UserContext); // 結果: undefined
return (
<UserContext.Provider value={{ user: 'Jane Doe' }}>
<Sidebar />
</UserContext.Provider>
);
}
解決策: 上位の App コンポーネントをラップするか、専用の ContextProvider ラッパーを作成して、データがグローバルに利用可能であることを確認してください。
2. 「セーフフック(Safe Hook)」パターン
すべてのファイルで useContext とコンテキストオブジェクトをインポートする代わりに、カスタムフックを作成することをお勧めします。これにより手間が省け、JavaScript の一般的なクラッシュよりもはるかに役立つエラーメッセージを表示できます。
// UserContext.js
import { createContext, useContext, useState } from 'react';
const UserContext = createContext(null);
export function UserProvider({ children }) {
const [user, setUser] = useState({ id: 1, name: 'Guest' });
return (
<UserContext.Provider value={{ user, setUser }}>
{children}
</UserContext.Provider>
);
}
export function useUser() {
const context = useContext(UserContext);
if (!context) {
throw new Error('useUser must be used within a UserProvider. Check your component tree!');
}
return context;
}
カスタムエラーをスローすることで、スタックトレースを追いかける代わりに、どの Provider が足りないのかをわずか数秒で特定できるようになります。
3. Next.js App Router の注意点
Next.js では、layout.js ファイルは Provider を配置するのに適した場所ですが、それらはクライアントコンポーネントである必要があります。Provider ファイルの先頭に "use client" ディレクティブを追加してください。また、layout.js は自身で定義したコンテキストを使用できないことに注意してください。アクセスできるのは、page.js や {children} 内の他の子コンポーネントのみです。
4. 循環参照の問題
AuthContext.js が Login.js をインポートし、Login.js が AuthContext.js をインポートしている場合、初期レンダリング時にコンテキストオブジェクトが undefined になってしまう可能性があります。これは大規模なアプリにおける静かな問題となります。createContext の呼び出しは、コンポーネントフォルダからのインポートがまったくない、小さく独立したファイルに常に保持するようにしてください。
修正を確認する方法
- React DevTools で調査する: ブラウザの DevTools を開き、「Components」タブに移動します。コンポーネントをクリックしてください。階層構造の中でその上に
Context.Providerが見当たらない場合、それが問題の原因です。 - 生のコンテキストをコンソールに出力する: 分割代入する前に、
console.log('Context Value:', useContext(MyContext))を追加してください。もしnullやundefinedと表示されたら、Provider の配置が間違っています。 - インポート名を確認する:
Contextオブジェクト自体をインポートするつもりで、誤ってProviderをインポートしていないか確認してください。
結論
useContext のエラーのほとんどは構造的なものです。このエラーが発生した場合、99% の確率で Provider をツリーのより高い位置に移動させるだけで解決します。プロダクションレベルのアプリでは、開発中にこれらの問題をユーザーに届く前にキャッチできるよう、セーフフックパターンを使用してください。

