Ojasa Mirai

Ojasa Mirai

ReactJS

Loading...

Learning Level

🟢 Beginner🔵 Advanced
🌍 Context API Basics📦 Creating Context🔌 Context.Provider🔍 useContext Hook🎯 Passing Data with Context🔄 Context with useState⚡ Context Performance🏗️ Context Best Practices
Reactjs/Context/Context Best Practices

🏗️ Context Best Practices — Building Clean Context Code

Following best practices helps you create maintainable, scalable Context implementations that other developers can easily understand and work with.


🎯 Create Custom Hooks for Context

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.

💡 Organize Contexts in Separate Files

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>

🎨 Real-World Example: Multi-Context Setup

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>
  );
}

📊 Best Practices Checklist

PracticeBenefitExample
Custom hooksError handling`useTheme()` throws if not wrapped
Separate filesOrganization`contexts/ThemeContext.tsx`
Clear namingReadability`useAuth`, `useTheme`, not `useCtx1`
Provider exportUsabilityExport both Provider and hook
Type safetyPrevents bugsDefine `ThemeContextType` interface
Provider stackingCleanStack Providers in root App

🔑 Key Takeaways

  • ✅ Create custom hooks instead of calling `useContext()` directly
  • ✅ Throw errors if Context is used outside its Provider
  • ✅ Put each Context in its own file
  • ✅ Export both the Provider component and the custom hook
  • ✅ Use clear, descriptive names for your Contexts
  • ✅ Stack Providers in your root App component
  • ✅ Use TypeScript interfaces for Context values
  • ✅ Group related Contexts together in a contexts folder

Ready to practice? Challenges | Quiz


Resources

Python Docs

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

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn