How would you create a reusable Context?
Assesses fundamental understanding of React conventions, runtime behavior, and memory/performance considerations.
Hiring managers look for precision, avoidance of ambiguous jargon, and ability to explain trade-offs under real production conditions.
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.
// 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;
}
// 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?
- Encapsulation: Consumers never import or touch the raw
Contextobject, so its internal shape can change without breaking callers. - Guardrails: The custom hook throws a clear error if used outside its provider, instead of silently returning
undefined. - Colocation: State, updater functions, and derived values live next to the provider, making the context self-contained and easy to test in isolation.
- Composability: Multiple reusable contexts (theme, auth, locale, etc.) can be combined by nesting providers, or composed with a helper that merges them.
- Performance-friendly: Memoizing the provider's value (with
useMemo) avoids creating a new object on every render, reducing unnecessary consumer re-renders (see [DoesReact.memoprevent Context consumers from re-rendering?](#does-reactmemo-prevent-context-consumers-from-re-rendering)).
Candidate Response Strategy & Interview Tips
- Start with a concise one-sentence summary: Deliver a direct, confident answer first before expanding into nuances.
- Demonstrate real-world trade-offs: Discuss where this approach excels and when you would avoid it in production systems.
- Discuss complexity & edge cases: Proactively explain time/space complexity or boundary conditions (null values, scale limits).
- Prepare for interviewer follow-ups: Technical hiring panels frequently probe deeper into concurrency, backward compatibility, or alternative libraries.