docs: Refactor context provider usage (#7793)

* delete provider

* Fix NavContext usage in Talks component

* Fix TocContext and LanguagesContext usage in Page component

* Fix IllustrationContext usage in IllustrationBlock component

* Fix LevelContext and TasksContext usage in managing-state.md

* Fix ThemeContext and Context usage in MyApp component

* Fix HighlightContext usage in List component

* Fix ThemeContext usage in MyApp component

* Fix ErrorDecoderContext usage in ErrorDecoderPage component

* Fix ThemeContext usage in MyPage and MyApp components

* Fix ThemeContext usage in MyApp component

* Fix useContext documentation to correct context provider references

* Fix context provider references in createContext documentation

* prettier

* Update src/content/reference/react/createContext.md

---------

Co-authored-by: Ricky <rickhanlonii@gmail.com>
This commit is contained in:
minami yoshihiko
2025-06-04 01:29:34 +09:00
committed by GitHub
parent 87cef4a918
commit c60173f9a4
13 changed files with 124 additions and 125 deletions

View File

@@ -1172,7 +1172,7 @@ async function Talks({ confId }) {
</CodeBlock>
}
right={
<NavContext.Provider value={{slug, navigate}}>
<NavContext value={{slug, navigate}}>
<BrowserChrome
domain="example.com"
path={'confs/' + slug}
@@ -1192,7 +1192,7 @@ async function Talks({ confId }) {
</Suspense>
</ExamplePanel>
</BrowserChrome>
</NavContext.Provider>
</NavContext>
}
/>
);

View File

@@ -82,11 +82,9 @@ export function Page({
'max-w-7xl mx-auto',
section === 'blog' && 'lg:flex lg:flex-col lg:items-center'
)}>
<TocContext.Provider value={toc}>
<LanguagesContext.Provider value={languages}>
{children}
</LanguagesContext.Provider>
</TocContext.Provider>
<TocContext value={toc}>
<LanguagesContext value={languages}>{children}</LanguagesContext>
</TocContext>
</div>
{!isBlogIndex && (
<DocsPageFooter

View File

@@ -354,7 +354,7 @@ function IllustrationBlock({
</figure>
));
return (
<IllustrationContext.Provider value={isInBlockTrue}>
<IllustrationContext value={isInBlockTrue}>
<div className="relative group before:absolute before:-inset-y-16 before:inset-x-0 my-16 mx-0 2xl:mx-auto max-w-4xl 2xl:max-w-6xl">
{sequential ? (
<ol className="mdx-illustration-block flex">
@@ -369,7 +369,7 @@ function IllustrationBlock({
)}
<AuthorCredit author={author} authorLink={authorLink} />
</div>
</IllustrationContext.Provider>
</IllustrationContext>
);
}

View File

@@ -741,9 +741,9 @@ export default function Section({ children }) {
const level = useContext(LevelContext);
return (
<section className="section">
<LevelContext.Provider value={level + 1}>
<LevelContext value={level + 1}>
{children}
</LevelContext.Provider>
</LevelContext>
</section>
);
}
@@ -836,13 +836,13 @@ export function TasksProvider({ children }) {
);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider
<TasksContext value={tasks}>
<TasksDispatchContext
value={dispatch}
>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
);
}

View File

@@ -461,11 +461,11 @@ export default function TaskApp() {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
// ...
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
...
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
);
}
```
@@ -509,8 +509,8 @@ export default function TaskApp() {
}
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
<h1>Day off in Kyoto</h1>
<AddTask
onAddTask={handleAddTask}
@@ -520,8 +520,8 @@ export default function TaskApp() {
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
/>
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
);
}
@@ -676,13 +676,13 @@ In the next step, you will remove prop passing.
Now you don't need to pass the list of tasks or the event handlers down the tree:
```js {4-5}
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
<h1>Day off in Kyoto</h1>
<AddTask />
<TaskList />
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
```
Instead, any component that needs the task list can read it from the `TaskContext`:
@@ -730,13 +730,13 @@ export default function TaskApp() {
);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
<h1>Day off in Kyoto</h1>
<AddTask />
<TaskList />
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
);
}
@@ -921,11 +921,11 @@ export function TasksProvider({ children }) {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
);
}
```
@@ -963,11 +963,11 @@ export function TasksProvider({ children }) {
);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
);
}
@@ -1174,11 +1174,11 @@ export function TasksProvider({ children }) {
);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
);
}

View File

@@ -260,9 +260,9 @@ export default function MyApp() {
const [theme, setTheme] = useState<Theme>('light');
return (
<ThemeContext.Provider value={theme}>
<ThemeContext value={theme}>
<MyComponent />
</ThemeContext.Provider>
</ThemeContext>
)
}
@@ -310,9 +310,9 @@ export default function MyApp() {
const object = useMemo(() => ({ kind: "complex" }), []);
return (
<Context.Provider value={object}>
<Context value={object}>
<MyComponent />
</Context.Provider>
</Context>
)
}

View File

@@ -1814,9 +1814,9 @@ function Form() {
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<ThemeContext value="dark">
<Form />
</ThemeContext.Provider>
</ThemeContext>
)
}
```
@@ -1900,9 +1900,9 @@ function Form() {
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<ThemeContext value="dark">
<Form />
</ThemeContext.Provider>
</ThemeContext>
)
}
```

View File

@@ -414,9 +414,9 @@ export default function List({ items, renderItem }) {
{items.map((item, index) => {
const isHighlighted = index === selectedIndex;
return (
<HighlightContext.Provider key={item.id} value={isHighlighted}>
<HighlightContext key={item.id} value={isHighlighted}>
{renderItem(item)}
</HighlightContext.Provider>
</HighlightContext>
);
})}
```
@@ -472,12 +472,12 @@ export default function List({ items, renderItem }) {
{items.map((item, index) => {
const isHighlighted = index === selectedIndex;
return (
<HighlightContext.Provider
<HighlightContext
key={item.id}
value={isHighlighted}
>
{renderItem(item)}
</HighlightContext.Provider>
</HighlightContext>
);
})}
<hr />

View File

@@ -38,14 +38,15 @@ const ThemeContext = createContext('light');
`createContext` returns a context object.
**The context object itself does not hold any information.** It represents _which_ context other components read or provide. Typically, you will use [`SomeContext.Provider`](#provider) in components above to specify the context value, and call [`useContext(SomeContext)`](/reference/react/useContext) in components below to read it. The context object has a few properties:
**The context object itself does not hold any information.** It represents _which_ context other components read or provide. Typically, you will use [`SomeContext`](#provider) in components above to specify the context value, and call [`useContext(SomeContext)`](/reference/react/useContext) in components below to read it. The context object has a few properties:
* `SomeContext.Provider` lets you provide the context value to components.
* `SomeContext` lets you provide the context value to components.
* `SomeContext.Consumer` is an alternative and rarely used way to read the context value.
* `SomeContext.Provider` is a legacy way to provide the context value before React 19.
---
### `SomeContext.Provider` {/*provider*/}
### `SomeContext` {/*provider*/}
Wrap your components into a context provider to specify the value of this context for all components inside:
@@ -54,9 +55,9 @@ function App() {
const [theme, setTheme] = useState('light');
// ...
return (
<ThemeContext.Provider value={theme}>
<ThemeContext value={theme}>
<Page />
</ThemeContext.Provider>
</ThemeContext>
);
}
```
@@ -141,11 +142,11 @@ function App() {
// ...
return (
<ThemeContext.Provider value={theme}>
<AuthContext.Provider value={currentUser}>
<ThemeContext value={theme}>
<AuthContext value={currentUser}>
<Page />
</AuthContext.Provider>
</ThemeContext.Provider>
</AuthContext>
</ThemeContext>
);
}
```
@@ -187,11 +188,11 @@ import { ThemeContext, AuthContext } from './Contexts.js';
function App() {
// ...
return (
<ThemeContext.Provider value={theme}>
<AuthContext.Provider value={currentUser}>
<ThemeContext value={theme}>
<AuthContext value={currentUser}>
<Page />
</AuthContext.Provider>
</ThemeContext.Provider>
</AuthContext>
</ThemeContext>
);
}
```

View File

@@ -226,12 +226,12 @@ export default function MyApp() {
}
return (
<ThemeContext.Provider value={theme}>
<ThemeContext value={theme}>
<button onClick={handleClick}>
Switch theme
</button>
<Greeting name="Taylor" />
</ThemeContext.Provider>
</ThemeContext>
);
}

View File

@@ -74,9 +74,9 @@ To pass context to a `Button`, wrap it or one of its parent components into the
```js [[1, 3, "ThemeContext"], [2, 3, "\\"dark\\""], [1, 5, "ThemeContext"]]
function MyPage() {
return (
<ThemeContext.Provider value="dark">
<ThemeContext value="dark">
<Form />
</ThemeContext.Provider>
</ThemeContext>
);
}
@@ -116,9 +116,9 @@ const ThemeContext = createContext(null);
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<ThemeContext value="dark">
<Form />
</ThemeContext.Provider>
</ThemeContext>
)
}

View File

@@ -38,11 +38,11 @@ function MyComponent() {
#### Returns {/*returns*/}
`useContext` returns the context value for the calling component. It is determined as the `value` passed to the closest `SomeContext.Provider` above the calling component in the tree. If there is no such provider, then the returned value will be the `defaultValue` you have passed to [`createContext`](/reference/react/createContext) for that context. The returned value is always up-to-date. React automatically re-renders components that read some context if it changes.
`useContext` returns the context value for the calling component. It is determined as the `value` passed to the closest `SomeContext` above the calling component in the tree. If there is no such provider, then the returned value will be the `defaultValue` you have passed to [`createContext`](/reference/react/createContext) for that context. The returned value is always up-to-date. React automatically re-renders components that read some context if it changes.
#### Caveats {/*caveats*/}
* `useContext()` call in a component is not affected by providers returned from the *same* component. The corresponding `<Context.Provider>` **needs to be *above*** the component doing the `useContext()` call.
* `useContext()` call in a component is not affected by providers returned from the *same* component. The corresponding `<Context>` **needs to be *above*** the component doing the `useContext()` call.
* React **automatically re-renders** all the children that use a particular context starting from the provider that receives a different `value`. The previous and the next values are compared with the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. Skipping re-renders with [`memo`](/reference/react/memo) does not prevent the children receiving fresh context values.
* If your build system produces duplicates modules in the output (which can happen with symlinks), this can break context. Passing something via context only works if `SomeContext` that you use to provide context and `SomeContext` that you use to read it are ***exactly* the same object**, as determined by a `===` comparison.
@@ -70,9 +70,9 @@ To pass context to a `Button`, wrap it or one of its parent components into the
```js [[1, 3, "ThemeContext"], [2, 3, "\\"dark\\""], [1, 5, "ThemeContext"]]
function MyPage() {
return (
<ThemeContext.Provider value="dark">
<ThemeContext value="dark">
<Form />
</ThemeContext.Provider>
</ThemeContext>
);
}
@@ -98,9 +98,9 @@ const ThemeContext = createContext(null);
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<ThemeContext value="dark">
<Form />
</ThemeContext.Provider>
</ThemeContext>
)
}
@@ -183,14 +183,14 @@ Often, you'll want the context to change over time. To update context, combine i
function MyPage() {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<ThemeContext value={theme}>
<Form />
<Button onClick={() => {
setTheme('light');
}}>
Switch to light theme
</Button>
</ThemeContext.Provider>
</ThemeContext>
);
}
```
@@ -213,7 +213,7 @@ const ThemeContext = createContext(null);
export default function MyApp() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<ThemeContext value={theme}>
<Form />
<label>
<input
@@ -225,7 +225,7 @@ export default function MyApp() {
/>
Use dark mode
</label>
</ThemeContext.Provider>
</ThemeContext>
)
}
@@ -317,14 +317,14 @@ const CurrentUserContext = createContext(null);
export default function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
return (
<CurrentUserContext.Provider
<CurrentUserContext
value={{
currentUser,
setCurrentUser
}}
>
<Form />
</CurrentUserContext.Provider>
</CurrentUserContext>
);
}
@@ -411,8 +411,8 @@ export default function MyApp() {
const [theme, setTheme] = useState('light');
const [currentUser, setCurrentUser] = useState(null);
return (
<ThemeContext.Provider value={theme}>
<CurrentUserContext.Provider
<ThemeContext value={theme}>
<CurrentUserContext
value={{
currentUser,
setCurrentUser
@@ -429,8 +429,8 @@ export default function MyApp() {
/>
Use dark mode
</label>
</CurrentUserContext.Provider>
</ThemeContext.Provider>
</CurrentUserContext>
</ThemeContext>
)
}
@@ -596,16 +596,16 @@ export default function MyApp() {
function MyProviders({ children, theme, setTheme }) {
const [currentUser, setCurrentUser] = useState(null);
return (
<ThemeContext.Provider value={theme}>
<CurrentUserContext.Provider
<ThemeContext value={theme}>
<CurrentUserContext
value={{
currentUser,
setCurrentUser
}}
>
{children}
</CurrentUserContext.Provider>
</ThemeContext.Provider>
</CurrentUserContext>
</ThemeContext>
);
}
@@ -775,11 +775,11 @@ export function TasksProvider({ children }) {
);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
</TasksDispatchContext>
</TasksContext>
);
}
@@ -978,9 +978,9 @@ export default function MyApp() {
const [theme, setTheme] = useState('light');
return (
<>
<ThemeContext.Provider value={theme}>
<ThemeContext value={theme}>
<Form />
</ThemeContext.Provider>
</ThemeContext>
<Button onClick={() => {
setTheme(theme === 'dark' ? 'light' : 'dark');
}}>
@@ -1067,13 +1067,13 @@ function Button({ children, onClick }) {
You can override the context for a part of the tree by wrapping that part in a provider with a different value.
```js {3,5}
<ThemeContext.Provider value="dark">
<ThemeContext value="dark">
...
<ThemeContext.Provider value="light">
<ThemeContext value="light">
<Footer />
</ThemeContext.Provider>
</ThemeContext>
...
</ThemeContext.Provider>
</ThemeContext>
```
You can nest and override providers as many times as you need.
@@ -1093,9 +1093,9 @@ const ThemeContext = createContext(null);
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<ThemeContext value="dark">
<Form />
</ThemeContext.Provider>
</ThemeContext>
)
}
@@ -1104,9 +1104,9 @@ function Form() {
<Panel title="Welcome">
<Button>Sign up</Button>
<Button>Log in</Button>
<ThemeContext.Provider value="light">
<ThemeContext value="light">
<Footer />
</ThemeContext.Provider>
</ThemeContext>
</Panel>
);
}
@@ -1230,9 +1230,9 @@ export default function Section({ children }) {
const level = useContext(LevelContext);
return (
<section className="section">
<LevelContext.Provider value={level + 1}>
<LevelContext value={level + 1}>
{children}
</LevelContext.Provider>
</LevelContext>
</section>
);
}
@@ -1302,9 +1302,9 @@ function MyApp() {
}
return (
<AuthContext.Provider value={{ currentUser, login }}>
<AuthContext value={{ currentUser, login }}>
<Page />
</AuthContext.Provider>
</AuthContext>
);
}
```
@@ -1330,9 +1330,9 @@ function MyApp() {
}), [currentUser, login]);
return (
<AuthContext.Provider value={contextValue}>
<AuthContext value={contextValue}>
<Page />
</AuthContext.Provider>
</AuthContext>
);
}
```
@@ -1349,8 +1349,8 @@ Read more about [`useMemo`](/reference/react/useMemo#skipping-re-rendering-of-co
There are a few common ways that this can happen:
1. You're rendering `<SomeContext.Provider>` in the same component (or below) as where you're calling `useContext()`. Move `<SomeContext.Provider>` *above and outside* the component calling `useContext()`.
2. You may have forgotten to wrap your component with `<SomeContext.Provider>`, or you might have put it in a different part of the tree than you thought. Check whether the hierarchy is right using [React DevTools.](/learn/react-developer-tools)
1. You're rendering `<SomeContext>` in the same component (or below) as where you're calling `useContext()`. Move `<SomeContext>` *above and outside* the component calling `useContext()`.
2. You may have forgotten to wrap your component with `<SomeContext>`, or you might have put it in a different part of the tree than you thought. Check whether the hierarchy is right using [React DevTools.](/learn/react-developer-tools)
3. You might be running into some build issue with your tooling that causes `SomeContext` as seen from the providing component and `SomeContext` as seen by the reading component to be two different objects. This can happen if you use symlinks, for example. You can verify this by assigning them to globals like `window.SomeContext1` and `window.SomeContext2` and then checking whether `window.SomeContext1 === window.SomeContext2` in the console. If they're not the same, fix that issue on the build tool level.
### I am always getting `undefined` from my context although the default value is different {/*i-am-always-getting-undefined-from-my-context-although-the-default-value-is-different*/}
@@ -1359,9 +1359,9 @@ You might have a provider without a `value` in the tree:
```js {1,2}
// 🚩 Doesn't work: no value prop
<ThemeContext.Provider>
<ThemeContext>
<Button />
</ThemeContext.Provider>
</ThemeContext>
```
If you forget to specify `value`, it's like passing `value={undefined}`.
@@ -1370,18 +1370,18 @@ You may have also mistakingly used a different prop name by mistake:
```js {1,2}
// 🚩 Doesn't work: prop should be called "value"
<ThemeContext.Provider theme={theme}>
<ThemeContext theme={theme}>
<Button />
</ThemeContext.Provider>
</ThemeContext>
```
In both of these cases you should see a warning from React in the console. To fix them, call the prop `value`:
```js {1,2}
// ✅ Passing the value prop
<ThemeContext.Provider value={theme}>
<ThemeContext value={theme}>
<Button />
</ThemeContext.Provider>
</ThemeContext>
```
Note that the [default value from your `createContext(defaultValue)` call](#specifying-a-fallback-default-value) is only used **if there is no matching provider above at all.** If there is a `<SomeContext.Provider value={undefined}>` component somewhere in the parent tree, the component calling `useContext(SomeContext)` *will* receive `undefined` as the context value.
Note that the [default value from your `createContext(defaultValue)` call](#specifying-a-fallback-default-value) is only used **if there is no matching provider above at all.** If there is a `<SomeContext value={undefined}>` component somewhere in the parent tree, the component calling `useContext(SomeContext)` *will* receive `undefined` as the context value.

View File

@@ -26,7 +26,7 @@ export default function ErrorDecoderPage({
);
return (
<ErrorDecoderContext.Provider value={{errorMessage, errorCode}}>
<ErrorDecoderContext value={{errorMessage, errorCode}}>
<Page
toc={[]}
meta={{
@@ -48,7 +48,7 @@ export default function ErrorDecoderPage({
<ErrorDecoder />
</MaxWidth> */}
</Page>
</ErrorDecoderContext.Provider>
</ErrorDecoderContext>
);
}