Suppose a dashboard has a user name at the top of its component tree, but only a button several layers down displays it. Passing the name through components that never use it is prop drilling. React context lets a provider make a value available to descendants without those intermediate props. section 10.1.1
Provide and read a value
Create a context outside your components, wrap the relevant tree, and read the value where it is needed: import { createContext, useContext } from 'react'; const NameContext = createContext('Guest'); function UserButton() { const name = useContext(NameContext); return <button>👤 {name}</button>; } function Dashboard() { return ( <NameContext.Provider value="Ada"> <UserButton /> </NameContext.Provider> ); } The provider supplies its value to descendants; useContext reads it in UserButton. If no matching provider is above the button, it reads the default value, 'Guest'. section 10.1.1 section 10.1.3 section 10.6
A context has a Provider and a Consumer. In function components, useContext is usually the simpler way to consume it. The alternative, Context.Consumer, takes a function that renders from the value and is mainly used in older class-based projects. A consumer reads from the nearest provider of the same context, so different parts of a tree can receive different values. section 10.1.3 section 10.6
Listing 10.4 Border width by context
import { useContext, createContext } from "react";
const BorderContext = createContext(1); #1
function Button({ children }) {
const borderWidth = useContext(BorderContext); #2
const style = {
border: `${borderWidth}px solid black`,
background: "transparent",
};
return <button style={style}>{children}</button>;
}
function CartButton() {
return (
<BorderContext.Provider value={5}> #3
<Button>Cart</Button>
</BorderContext.Provider>
);
}
function Header() {
const style = {
padding: "5px",
borderBottom: "1px solid black",
marginBottom: "10px",
display: "flex",
gap: "5px",
justifyContent: "flex-end",
};
return (
<header style={style}>
<Button>Clothes</Button>
<Button>Toys</Button>
<CartButton />
</header>
);
}
function Footer() {
const style = {
padding: "5px",
borderTop: "1px solid black",
marginTop: "10px",
display: "flex",
justifyContent: "space-between",
};
return (
<footer style={style}>
<Button>About</Button>
<Button>Jobs</Button>
<CartButton />
</footer>
);
}
function App() {
return (
<main>
<Header />
<h1>Welcome to the shop!</h1>
<BorderContext.Provider value={2}> #4
<Footer />
</BorderContext.Provider>
</main>
);
}
export default App;
Inspect how one button reads a default border width while a provider gives a nested button a different width. The button itself does not need a border-width prop. section 10.1.3
For a menu whose links must be available throughout an application, export a context from a shared file, place its provider around the application, and call useContext in the menu. An empty-array default gives consumers an empty list if no provider is present. Context removes repetitive handoffs; put the provider around the components that need its value. section 11.4 section 11.4.1 section 11.4.2


