ProgramGuru

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.

  1. Provide a value

    Place a shared value above its readers.

  2. Read the nearest value

    Use the same context object in consumers.

  3. Choose a scope

    Prefer props when the information is local and explicit.

Follow information through the application

  1. Owner

    App stores the chosen school name.

  2. Provider

    The shared context makes that value available below.

  3. Readers

    Header and Report read the closest provider.

Read this relationship alongside the complete code. This diagram explains the flow; it does not execute React.

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

Where is the school name actually stored in this example?
Choose one answer. You can try again.

Answer and explanation

In App’s useState, then passed through the provider.

Correct. Context transports the owner’s current value.

Apply the scope rule

Two nested providers supply different school names. Which does a reader use?
Choose one answer. You can try again.

Answer and explanation

The nearest matching provider above that reader.

Correct. Nested providers can intentionally override a subtree’s value.

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.

    Next lesson: Organize a React Project →