
ReactJS
Following best practices helps you create maintainable, scalable Context implementations that other developers can easily understand and work with.
Instead of calling `useContext()` directly, create a custom hook. This provides a single point of error handling:
import { createContext, useContext } from "react";
const ThemeContext = createContext<{ theme: string } | undefined>(undefined);
// ✅ Good: Custom hook with error handling
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within ThemeProvider");
}
return context;
}
// Component code is cleaner
function Header() {
const { theme } = useTheme(); // Clear error if not inside Provider
return <header style={{ background: theme }}>Header</header>;
}Custom hooks are clearer than raw `useContext()` calls and catch bugs early.
For large apps, put each Context in its own file with its Provider:
// contexts/ThemeContext.tsx
import { createContext, useContext, useState, ReactNode } from "react";
type Theme = "light" | "dark";
interface ThemeContextType {
theme: Theme;
setTheme: (theme: Theme) => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<Theme>("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within ThemeProvider");
}
return context;
}
// App.tsx
import { ThemeProvider, useTheme } from "./contexts/ThemeContext";
function Header() {
const { theme, setTheme } = useTheme();
return <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>;
}
function App() {
return (
<ThemeProvider>
<Header />
</ThemeProvider>
);
}<details>
<summary>📚 More Examples</summary>
// contexts/AuthContext.tsx
import { createContext, useContext, useState, ReactNode } from "react";
interface User {
id: string;
name: string;
email: string;
}
interface AuthContextType {
user: User | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const login = async (email: string, password: string) => {
// Call API...
setUser({ id: "1", name: "Alice", email });
};
const logout = () => {
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within AuthProvider");
}
return context;
}
// Combine multiple contexts in App
import { ThemeProvider } from "./contexts/ThemeContext";
import { AuthProvider } from "./contexts/AuthContext";
function App() {
return (
<AuthProvider>
<ThemeProvider>
<MainApp />
</ThemeProvider>
</AuthProvider>
);
}</details>
A well-organized app combines multiple Contexts:
// src/contexts/index.ts - Export all contexts
export { ThemeProvider, useTheme } from "./ThemeContext";
export { AuthProvider, useAuth } from "./AuthContext";
export { NotificationProvider, useNotification } from "./NotificationContext";
// src/App.tsx - Stack Providers
import {
ThemeProvider,
AuthProvider,
NotificationProvider,
} from "./contexts";
export default function App() {
return (
<AuthProvider>
<ThemeProvider>
<NotificationProvider>
<MainApp />
</NotificationProvider>
</ThemeProvider>
</AuthProvider>
);
}
// src/components/Header.tsx - Use custom hooks
import { useAuth } from "../contexts";
function Header() {
const { user } = useAuth();
return (
<header>
{user ? <p>Welcome, {user.name}</p> : <p>Please log in</p>}
</header>
);
}| Practice | Benefit | Example |
|---|---|---|
| Custom hooks | Error handling | `useTheme()` throws if not wrapped |
| Separate files | Organization | `contexts/ThemeContext.tsx` |
| Clear naming | Readability | `useAuth`, `useTheme`, not `useCtx1` |
| Provider export | Usability | Export both Provider and hook |
| Type safety | Prevents bugs | Define `ThemeContextType` interface |
| Provider stacking | Clean | Stack Providers in root App |
Ready to practice? Challenges | Quiz
Resources
Ojasa Mirai
Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.
Learn Deep • Build Real • Verify Skills • Launch Forward