https://github.com/chantastic/reactcontext.com
a gentle intro to the what, where, when, why, and how of React Context
https://github.com/chantastic/reactcontext.com
Last synced: about 1 year ago
JSON representation
a gentle intro to the what, where, when, why, and how of React Context
- Host: GitHub
- URL: https://github.com/chantastic/reactcontext.com
- Owner: chantastic
- Created: 2018-03-26T18:22:46.000Z (about 8 years ago)
- Default Branch: main
- Last Pushed: 2025-01-21T20:17:16.000Z (over 1 year ago)
- Last Synced: 2025-03-28T20:36:40.212Z (about 1 year ago)
- Language: Astro
- Homepage: http://reactcontext.com
- Size: 242 KB
- Stars: 9
- Watchers: 2
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# React Context
*Updated for React 19.*
## TLDR on React Context
Use Context for *implicit*, client-only, data distribution.
Context is an alternative props (which are *explicit* and available to both server and client components).
Context allows for component relationships similar to HTML elements `
- `.
- Tenth
- Eleventh
- Twelfth
-
{post.body}
Here, data applied to the parent, has an implicit impact on how children render.
```jsx title="an HTML comparison"
```
Context makes a value available to all descendents.
```jsx title="parent providing context"
```
Those descendents must opt in to Context.
```jsx title="child component using context"
function UserAvatar() {
let user = React.use(UserContext);
return ;
}
```
Unlike HTML, Context does not require direct parent-child relationships.
Contexts can be sent and recieved *"thru"* intermediate elements, components, and context providers.
```jsx title="child composing two contexts"
```
This doc is a guide for implementing Context in React.
## Table of contents
## Real-world React Context (a "shit" example)
*Shit* is fine word in my house. But my mom hates it.
So I tell my kids to use another word when around grandma.
Here's how I'd implement that with React Context.
```jsx
// It's ok to say "shit" as a default expletive
let ExpletiveContext = React.createContext("shit");
// But context is important. Learn to account for it.
function ContextualExclamation() {
let word = React.use(ExpletiveContext);
return Oh {word}!;
}
// When at Grandma's house, say "snap" instead
function AtGrandmasHouse() {
return (
)
);
// => Oh snap!
```
## Context is a 3-part system: create, use, and provide
Context is a 3-part system:
**create**, **use**, **provide**.
**Create** context with `React.createContext`.
```jsx title="create context"
let NameContext = React.createContext("Guest");
```
**Use** context with `React.use`.
```jsx title="use context"
function ContextualGreeting() {
let name = React.use(NameContext);
return
👋 {name}!
;}
```
**Provide** context by rendering the `Context` with a `value` prop.
```jsx title="provide context value"
// =>
👋 Chan!
```
## Context is an alternative to props that is implicit
Context is most useful when many components require the same data.
Here's an example:
```jsx title="app.jsx"
<>
>
```
These components may, in turn, also pass the same data to their children.
```jsx title="user_avatar.jsx" {9}
function UserRelatedPosts({ user }) {
const related_posts = getRelatedPosts(user);
return (
{related_posts.map(post => (
))}
);
}
```
With Context, the data is set once on the parent.
```jsx title="app.jsx" ins=/(UserContext.*)>/ del=/ user={user}/
```
And descendent components opt into this data with `use`.
```jsx title="user_avatar.jsx" ins=/const user =.+/ del=/{ user }/
function UserAvatar({ user }) {
const user = React.use(UserContext);
return ;
}
```
## Think of props like wired and Context like wireless (a mental model)
**Props are like wires.**
They "connect" data between components.
Like wires, the components have to be "touching".
Meaning that components *holding* data have to render components that *need* it.
**Context is like a wireless.**
It sends a "signal" that is received by children.
Like wireless, components don't need to be "touching" they only need to be "in range".
Meaning that children of context can *recieve* the signal that context sends.
## Context is available to all descendents (indifferent to how deeply nested)
Every descendent/child of a Context provider can observe Context's value.
```jsx title="any descendent can recieve context" {4, 7, 10}
function App() {
return (
{/* UserContext can be received here… */}
{/* also here… */}
{/* and anywhere in this tree… */}
);
}
```
## Context is composable
Contexts can be chidren of other Contexts. Order doesn't matter much unless it matters to your app.
```jsx title="two contexts; one component"
let OrgContext = React.createContext();
let PersonContext = React.createContext();
function App() {
return (
);
}
function UserOrgBizCard() {
const org_name = React.use(OrgContext);
const person_name = React.use(PersonContext);
return (
{person_name}, {org_name}
);
}
```
## Context can not be sent "over the wire" (it's not available to the server)
Context is only available to client components.
Server components cannot recieve context.
## Context is used to implement the compound components pattern
The "compound component" pattern describes components that are isolated but interdependent.
In HTML, `li` and `ol` are interdepedent. As are `option` and `select`.
This same interdependent relationship can be implemented using React Context.
```jsx title="app.jsx"
import * as React from "react";
import * as User from "./user";
function App() {
const [editing, setEditing] = React.useState(false);
const [user, setUser] = React.useState({
name: "Guest",
avatar_url: "https://example.com/avatar.png"
});
return (
{isEditing
? {
setUser({ name: formData.get('name') });
setEditing(false);
}}
/>
: <>
setEditing(true)}>
Edit
>
}
);
}
```
```jsx title="user.jsx"
import * as React from "react";
export const Context = React.createContext();
function Avatar() {
const user = React.use(UserContext);
return
}
function Name() {
const user = React.use(UserContext);
return (
{user.name}
);
}
function Form({ action }) {
const user = React.use(UserContext);
return (
);
}
```
## Context can be used to implement distributed state management (with useReducer)
Context makes it possible to distribute data to every component in a component tree.
It's used to distribute data, not manage state.
That said, it provides the mechanism needed to both distribute state and dispatch updates.
Here's an minimum connection of the two.
```jsx title="app.jsx"
import * as React from 'react';
import * as ClickCount from './click_count';
function App() {
const clickState = React.useReducer(
ClickCount.reducer,
ClickCount.initialState
);
return (
);
}
```
```jsx title="click_count.jsx"
import * as React from 'react';
export const initialState = { count: 0 };
export function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
default:
return state;
}
}
export const Context = React.createContext();
export function Show() {
let [state] = React.use(Context);
return <>{state.count}>;
}
export function IncrementAction() {
let [, dispatch] = React.use(Context);
return (
dispatch({ type: 'increment' })}>
Increment count
);
}
```
## Any JavaScript value can be be shared via Context
Context can take any shape.
Here are examples of valid Contexts values, using a default `value`:
```jsx
let StringContext = React.createContext("string");
let NumberContext = React.createContext(42);
let FunctionContext = React.createContext(() =>
alert("Context function")
);
let ArrayContext = React.createContext([
"some",
"array",
"elements"
]);
let ObjectContext = React.createContext({
aString: "string",
aNumber: 42,
aFunction: () => alert("Context function"),
anArray: ["some", "array", "elements"]
});
let MapAndSetContext = React.createContext(
new Map([
[
'Taylor Swift',
new Set(['Tortured Poets Department', 'Midnights', 'Evermore']),
],
])
);
```
`value` can be complex structures like React Elements, class components, and function components.
```jsx
let ReactElementContext = React.createContext(
React Element
);
let FunctionalComponentContext = React.createContext(
props => Function Component
);
```
## You can set a default `value` when creating Context
Context can be initialized with a default `value`.
When a component attempts to `use` Context, but no corresponding `Context` is found, a default value will be used.
```jsx
let UserContext = React.createContext("Guest");
function UserGreeting () {
let name = React.use(UserContext);
return Hi {name}!;
}
let App = props => (
{/* => Hi Guest! */}
{/* => Hi Bulbasaur! */}
);
```
## Context can be used inline with the render prop pattern
Context exposes a `Consumer` component for inline context use. This allows context to be consumed without creating new components.
```jsx
{value => {value}}
```
Here's an example where multiple contexts are created and used.
```jsx
const OrgContext = React.createContext();
const PersonContext = React.createContext();
function App () {
return (
{organization => (
{person => (
{person}, {organization}
)}
)}
)
}
// => Yakko, ACME Co.
```
## Context can cascade
Consumers use the value from the nearest `Context`.
Where none is present, the `createContext` default value is used.
```jsx
const MyContext = React.createContext("default");
function ShowContextValue() {
const value = React.use(MyContext);
return <>{value}>;
}
function App() {
return (
<>
{/* "outer" */}
{/* "inner" */}
{/* "default" */}
>
);
}
```
## What is Legacy Context?
Legacy Context refers to a set of APIs that were removed in React 19.
These include class-based component context.
Read the [Legacy Context doc](https://reactjs.org/docs/legacy-context.html) for more details.
© 2024 Michael Chan, Some Rights Reserved

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.