Every context object created with createContext() comes with its own Provider component, which accepts a value prop, the actual data being shared, and renders its children normally, making that value available to any useContext(MyContext) call anywhere within those children, no matter how deeply nested. Multiple Providers for the same context can be nested, with a descendant's useContext call always reading from the nearest enclosing Provider above it in the tree, and if the value prop passed to a Provider is a new object or array on every parent render, even with logically identical contents, every consuming component re-renders unnecessarily, since object/array equality is checked by reference, not by deep content comparison.
1Understanding Provider
Every context object created with createContext() comes with its own Provider component, which accepts a value prop, the actual data being shared, and renders its children normally, making that value available to any useContext(MyContext) call anywhere within those children, no matter how deeply nested. Multiple Providers for the same context can be nested, with a descendant's useContext call always reading from the nearest enclosing Provider above it in the tree, and if the value prop passed to a Provider is a new object or array on every parent render, even with logically identical contents, every consuming component re-renders unnecessarily, since object/array equality is checked by reference, not by deep content comparison.
Wrap a Provider's value prop in useMemo when it's an object or array constructed inline in the parent's render, otherwise a brand-new object reference on every render causes every consuming component to unnecessarily re-render, even if the object's actual contents haven't logically changed.
const CountContext = createContext(0);
function App() {
return (
<CountContext.Provider value={5}>
<Display />
</CountContext.Provider>
);
}
function Display() {
const count = useContext(CountContext);
return <p>Count: {count}</p>;
}2Practical Example
Here is a real-world application of Provider showing how it is used in production React code.
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Section />
<ThemeContext.Provider value="light">
<NestedSection />
</ThemeContext.Provider>
</ThemeContext.Provider>
);
}3Best Practices
Follow these guidelines when working with Provider:
1. Memoize a Provider's value prop with useMemo whenever it's an object or array, to avoid giving every consumer a new reference, and therefore an unnecessary re-render, on every parent render
2. Nest multiple Providers for the same context deliberately when you specifically need different parts of the tree to see different values, since the nearest enclosing Provider always wins
3. Keep a Provider as close as reasonably possible to the components that actually need its value, rather than always wrapping the entire application, to limit the scope of re-renders it can trigger
Tip: Wrap a Provider's value prop in useMemo when it's an object or array constructed inline in the parent's render, otherwise a brand-new object reference on every render causes every consuming component to unnecessarily re-render, even if the object's actual contents haven't logically changed.
const CountContext = createContext(0);
function App() {
return (
<CountContext.Provider value={5}>
<Display />
</CountContext.Provider>
);
}
function Display() {
const count = useContext(CountContext);
return <p>Count: {count}</p>;
}