C

Context API

Type-safe React Context for global state management with proper typing for providers and consumers.

Code

typescript
1import React, { createContext, useContext, useState, useCallback, ReactNode } from "react";
2
3// Define the shape of your context
4interface User {
5 id: string;
6 name: string;
7 email: string;
8 role: "admin" | "user" | "guest";
9}
10
11interface AuthContextType {
12 user: User | null;
13 isAuthenticated: boolean;
14 login: (email: string, password: string) => Promise<void>;
15 logout: () => void;
16 updateUser: (updates: Partial<User>) => void;
17}
18
19// Create context with undefined default (will be provided by provider)
20const AuthContext = createContext<AuthContextType | undefined>(undefined);
21
22// Custom hook for using the context with type safety
23function useAuth(): AuthContextType {
24 const context = useContext(AuthContext);
25 if (context === undefined) {
26 throw new Error("useAuth must be used within an AuthProvider");
27 }
28 return context;
29}
30
31// Provider component
32interface AuthProviderProps {
33 children: ReactNode;
34}
35
36function AuthProvider({ children }: AuthProviderProps) {
37 const [user, setUser] = useState<User | null>(null);
38
39 const login = useCallback(async (email: string, password: string) => {
40 // Simulate API call
41 const response = await fetch("/api/login", {
42 method: "POST",
43 body: JSON.stringify({ email, password }),
44 });
45 const userData: User = await response.json();
46 setUser(userData);
47 }, []);
48
49 const logout = useCallback(() => {
50 setUser(null);
51 }, []);
52
53 const updateUser = useCallback((updates: Partial<User>) => {
54 setUser((prev) => (prev ? { ...prev, ...updates } : null));
55 }, []);
56
57 const value: AuthContextType = {
58 user,
59 isAuthenticated: user !== null,
60 login,
61 logout,
62 updateUser,
63 };
64
65 return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
66}
67
68// Theme context example with generics
69type Theme = "light" | "dark" | "system";
70
71interface ThemeContextType {
72 theme: Theme;
73 setTheme: (theme: Theme) => void;
74 resolvedTheme: "light" | "dark";
75}
76
77const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
78
79function useTheme() {
80 const context = useContext(ThemeContext);
81 if (!context) throw new Error("useTheme must be used within ThemeProvider");
82 return context;
83}
84
85// Usage in components
86function UserProfile() {
87 const { user, logout, isAuthenticated } = useAuth();
88 const { theme, setTheme } = useTheme();
89
90 if (!isAuthenticated) {
91 return <p>Please log in</p>;
92 }
93
94 return (
95 <div>
96 <h2>Welcome, {user?.name}</h2>
97 <p>Role: {user?.role}</p>
98 <button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
99 Toggle Theme
100 </button>
101 <button onClick={logout}>Logout</button>
102 </div>
103 );
104}
105
106// App with providers
107function App() {
108 return (
109 <AuthProvider>
110 <UserProfile />
111 </AuthProvider>
112 );
113}
114
115export { AuthProvider, useAuth, ThemeContext, useTheme };

Run this example locally

$ npm install react @types/react