Share Values with Context
Share Values with Context
A school name appears in the navigation, report heading and footer. Passing it through every intermediate layout component can be repetitive, especially when those layouts do not otherwise need to read the name.
Context lets a component provide a value to descendants that read the same context object. It changes how values travel through the tree; it does not automatically provide storage, remote fetching or a complete state-management architecture.
Provide a value
Place a shared value above its readers.
Read the nearest value
Use the same context object in consumers.
Choose a scope
Prefer props when the information is local and explicit.
Follow information through the application
Owner
App stores the chosen school name.
Provider
The shared context makes that value available below.
Readers
Header and Report read the closest provider.
The provider supplies, the reader subscribes
createContext declares a context object outside the components. Its default is a fallback for a reader with no matching provider above it. The provider’s value is the actual shared information. useContext reads that value and subscribes the component to changes in it.
The nearest matching provider above a reader wins. A provider returned by the same component does not supply a value to a useContext call earlier in that component; it supplies descendants. React’s useContext reference explains this tree relationship. The familiar Context.Provider spelling below is supported, including in React 19.
One school owner, two readers
Header and Report read the same SchoolContext. App owns the name with useState and passes a value object to the provider. Switch school updates that owner; both readers then display Hill School. Neither reader maintains a separate school-name state.
The explicit missing-provider error is an intentional configuration check. A null fallback helps expose a forgotten provider during development rather than showing a plausible but incorrect school. This example includes every component and creates no global browser variable.
React · JavaScript with JSX
import React, { createContext, useContext, useState } from 'react';
const SchoolContext = createContext(null);
function Header() {
const school = useContext(SchoolContext);
if (!school) throw new Error('School provider is missing');
return <h2>{school.name}</h2>;
}
function Report() {
const school = useContext(SchoolContext);
if (!school) throw new Error('School provider is missing');
return <p>Report heading: {school.name}</p>;
}
export default function App() {
const [name, setName] = useState('River School');
return <SchoolContext.Provider value={{ name }}>
<Header /><Report />
<button onClick={() => setName('Hill School')}>Switch school</button>
</SchoolContext.Provider>;
}Expected screen and behavior
Initially: River School, Report heading: River School and Switch school.
Switch school changes both names to Hill School.Context transports state; it does not own it
React · the provider and readers
import React, { createContext, useContext, useState } from 'react';
const SchoolContext = createContext(null);
function Header() {
const school = useContext(SchoolContext);
if (!school) throw new Error('School provider is missing');
return <h2>{school.name}</h2>;
}
function Report() {
const school = useContext(SchoolContext);
if (!school) throw new Error('School provider is missing');
return <p>Report heading: {school.name}</p>;
}
export default function App() {
const [name, setName] = useState('River School');
return <SchoolContext.Provider value={{ name }}>
<Header /><Report />
<button onClick={() => setName('Hill School')}>Switch school</button>
</SchoolContext.Provider>;
}The context object is not the current school name. App’s state owns that name, and the provider passes a snapshot of its current value. A state update produces another render and another provider value, which reaches consumers. Read this direction from owner to provider to readers.
Consumers can also receive a setter or dispatch function through a deliberate context interface. That enables changes at the owner rather than asking each consumer to invent its own shared state. A reducer with context can suit more complex shared transitions, but the extra structure should solve a real coordination problem.
Do not hide every dependency
Props remain useful when a child needs information from a nearby parent. A StudentCard receiving name and mark has an easy-to-read contract and can be tested in isolation. Context is more suitable for information many descendants need, such as the active school or display preferences.
Before adding context, consider component composition: a layout can receive already-created children without passing every underlying value itself. Context removes repetitive transport, but it can also make dependencies less visible. Name the context after its responsibility and put the provider at the lowest shared scope that serves its readers.
Worked practice: change the starting school
Start with Lake School instead of River School. Predict both initial labels and the result of Switch school. The complete answer changes only the owner’s initial state.
Both readers start with Lake School because they obtain their name from one provider. Switching still changes both to Hill School. Editing a hard-coded heading inside only Header would have created inconsistent information and defeated the shared-value design.
React · JavaScript with JSX
import React, { createContext, useContext, useState } from 'react';
const SchoolContext = createContext(null);
function Header() {
const school = useContext(SchoolContext);
if (!school) throw new Error('School provider is missing');
return <h2>{school.name}</h2>;
}
function Report() {
const school = useContext(SchoolContext);
if (!school) throw new Error('School provider is missing');
return <p>Report heading: {school.name}</p>;
}
export default function App() {
const [name, setName] = useState('Lake School');
return <SchoolContext.Provider value={{ name }}>
<Header /><Report />
<button onClick={() => setName('Hill School')}>Switch school</button>
</SchoolContext.Provider>;
}Expected screen and behavior
Initially: Lake School and Report heading: Lake School.
Switch school changes both names to Hill School.Scope updates and keep data rules separate
React compares provider values by identity. An inline object such as { name } is newly created on each App render; this can trigger context consumers when the value object changes. For a small app that may be acceptable. Measure before adding memoization, and consider splitting unrelated contexts rather than forcing every consumer to observe everything.
Context values are ordinary client data. Do not place server secrets in them, and do not treat the provider as an access-control boundary. State also resets if its owning provider unmounts. Choose a lifetime and persistence strategy according to the school workflow.
Check the owner
Apply the scope rule
Share through a deliberate tree boundary
Create one context object, provide the owner’s value above its consumers, and read it with useContext. Keep props for focused local interfaces. Understand provider lifetime and value identity before using context for larger shared state.
Review lifting state to a shared parent and composition for the ownership decisions that come before choosing how to transport a value.
Reaching the recap and completing the quizzes are separate milestones.