InterviewHubPRO
Section Overview
Q328

Question 328 of 445

Part 10: Modern React 18, React 19 & Next.js Patterns (317 - 353)

74%
React & Modern Frontend (445 Qs)•Part 10: Modern React 18, React 19 & Next.js Patterns (317 - 353)

How would you create a reusable Context?

A reusable Context bundles the createContext call, its Provider (with local state/logic), and a custom hook to consume it into a single module. This hides the raw Context object from consumers, provides a clear API, and lets you validate that the hook is used within its provider.

jsx
// ThemeContext.js
import { createContext, useContext, useMemo, useState } from "react";

const ThemeContext = createContext(undefined);

export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");

const toggleTheme = () =>
  setTheme((prev) => (prev === "light" ? "dark" : "light"));

// Memoize so the value reference is stable across renders
const value = useMemo(() => ({ theme, toggleTheme }), [theme]);

return (
  <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
);
}

// Custom hook consumers use instead of importing ThemeContext directly
export function useTheme() {
const context = useContext(ThemeContext);
if (context === undefined) {
  throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
}
jsx
// App.js
function App() {
return (
  <ThemeProvider>
    <Toolbar />
  </ThemeProvider>
);
}

function Toolbar() {
const { theme, toggleTheme } = useTheme();
return <button onClick={toggleTheme}>Current theme: {theme}</button>;
}

Why wrap Context like this?

  1. Encapsulation: Consumers never import or touch the raw Context object, so its internal shape can change without breaking callers.
  2. Guardrails: The custom hook throws a clear error if used outside its provider, instead of silently returning undefined.
  3. Colocation: State, updater functions, and derived values live next to the provider, making the context self-contained and easy to test in isolation.
  4. Composability: Multiple reusable contexts (theme, auth, locale, etc.) can be combined by nesting providers, or composed with a helper that merges them.
  5. Performance-friendly: Memoizing the provider's value (with useMemo) avoids creating a new object on every render, reducing unnecessary consumer re-renders (see Does React.memo prevent Context consumers from re-rendering?).