Type-Safe Context API
On this page
What Context Is For
- Cross cutting concerns used by many components: auth, theme, locale, feature flags.
- Not a general replacement for props or a global store.
- Production rule: keep context scope small and value stable.
Type Safe Context Pattern
- Create context with a nullable type.
- Expose a hook that throws if the provider is missing.
- This removes scattered null checks and fails fast in development and tests.
Example: Safe Hook
type AuthContextValue = {
userId: string;
logout: () => void;
};
const AuthContext = React.createContext<AuthContextValue | null>(null);
export function useAuth(): AuthContextValue {
const v = React.useContext(AuthContext);
if (!v) throw new Error("AuthProvider missing");
return v;
}
Provider Value Stability
- Provider values are often objects. Recreating them each render can re render all consumers.
- Memoize provider values when they contain objects or callbacks.
Example: Memoized Provider Value
function AuthProvider({ userId, children }) {
const logout = React.useCallback(() => {
// logout logic
}, []);
const value = React.useMemo(() => {
return { userId, logout };
}, [userId, logout]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
Split by Update Frequency
- One context that changes frequently can trigger wide re renders.
- Split contexts so high frequency updates do not impact low frequency consumers.
Failure Modes
- Nullable context used directly, causing null checks everywhere.
- Mega context includes many unrelated values and re renders large parts of the tree.
- Provider value recreated every render, causing unnecessary re renders.
- Context used for request data and server state, leading to caching and invalidation issues.
Production Checklist
- Context scope is small and clear.
- Safe hook enforces provider presence.
- Provider values are stable and memoized where needed.
- Contexts are split by responsibility and update frequency.