Context
ReactのContextはグローバル変数に等しいため、ClaudeCodeでも限定的な用途でのみ使用します。弊社では、多言語設定、ログイン状態、ユーザー情報など本当にグローバルな状態か、エディタなど複雑なコンポーネントでのProps Drilling回避でのみContextを使用します。
弊社の推奨ルール
- Contextは基本的に使用しない(グローバル変数と同等のため)
- 多言語、認証状態、ログイン中のユーザー情報のみ許可
- 複雑なコンポーネント(エディタ等)でのバケツリレー回避に使用
- ContextにはsetStateも含めて更新可能にする
- 複雑な状態更新はReducerと組み合わせる
- Contextの初期値にはProxyを使用してProvider設定忘れを検出する
ClaudeCodeでの利用
認証状態の管理
ログイン状態とユーザー情報を管理する基本的な用途
「ログイン状態とユーザー情報を管理するContextを作成して、setStateも含めて」
多言語対応の実装
アプリ全体で使用する言語設定を管理する
「多言語対応のContextを作成して、言語切り替え機能も含めて」
エディタコンポーネントでの使用
複雑なコンポーネントでバケツリレーを回避する
「エディタコンポーネント用のContextでバケツリレーを回避して」
ReducerとContextの組み合わせ
複雑な状態更新が必要な場合の実装
「認証ContextをReducerと組み合わせて複雑な状態管理を実装」
ProviderなしでContextを使用した場合のエラー検出
Contextの初期値にProxyを使用することで、Providerが設定されていない状態でContextを使用した場合に明確なエラーを発生させます。これにより、開発時にProviderの設定忘れを早期に発見できます。
// Context用の型定義
type AppContextValue = {
state: AppState;
dispatch: (action: AppAction) => void;
};
// ProviderなしでContext使用時にエラーを投げるProxy
const proxy = new Proxy({} as AppContextValue, {
get() {
throw new Error("AppContext must be provided");
}
});
// Contextの初期値にProxyを設定
export const AppContext = createContext<AppContextValue>(proxy);
このProxyパターンにより、Providerでラップされていないコンポーネントがcontextの任意のプロパティにアクセスしようとすると、即座にエラーが発生します。
// 使用例:認証Context
type AuthContextValue = {
isAuthenticated: boolean;
signOut(): Promise<null>;
signIn(email: string, password: string): Promise<null>;
refresh(): Promise<null>;
};
const authProxy = new Proxy({} as AuthContextValue, {
get() {
throw new Error("AuthContext must be provided");
}
});
export const AuthContext = createContext<AuthContextValue>(authProxy);
// ❌ Providerなしで使用するとエラー
function ComponentWithoutProvider() {
const { isAuthenticated } = useContext(AuthContext);
// Error: AuthContext must be provided (プロパティアクセス時に発生)
return <div>{isAuthenticated ? "ログイン済み" : "未ログイン"}</div>;
}
// ✅ Provider内で使用すれば正常動作
function App() {
const authValue: AuthContextValue = {
isAuthenticated: true,
signOut: async () => null,
signIn: async () => null,
refresh: async () => null
};
return (
<AuthContext.Provider value={authValue}>
<ComponentWithProvider />
</AuthContext.Provider>
);
}
弊社では、すべてのContextでこのProxyパターンを使用し、Provider設定忘れによるバグを防いでいます。
setStateを含めた更新可能なContext
Contextには値だけでなくsetStateも含めることで、どのコンポーネントからも状態を更新できるようにします。
// 認証Contextの例(setStateを含む)
type AuthContextValue = {
user: User | null;
isAuthenticated: boolean;
setUser: (user: User | null) => void;
setIsAuthenticated: (value: boolean) => void;
};
function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const value: AuthContextValue = {
user,
isAuthenticated,
setUser,
setIsAuthenticated
};
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
);
}
よくある問題
Contextを使うべきでない場合
テーマ設定などの頻繁に変わらない値以外は、基本的にContextを避けます。フォームの状態、UIの開閉状態などローカルな状態は、propsやカスタムフックで管理します。
グローバル変数としての認識不足
Contextはグローバル変数と同等です。弊社では、多言語設定、認証状態、ユーザー情報以外での使用を原則禁止しています。
エディタなど複雑なコンポーネントでの使用
エディタのような深い階層を持つ複雑なコンポーネントでは、Props Drilling回避のためContextを使用します。ただし、エディタコンポーネント内でのみ使用し、アプリ全体には影響しないよう設計します。