Context is "just" a prop with special behavior, like children
or key
. It implicitly propagates from elements to their children, unless it is explicitly overridden.
Context can be provided as a prop (to elements) or via the children
object's withContext
method. Context can be consumed as a prop (to components) or by using a function in children
.
This component:
const Container = ({ children }) => (
<section>
<Header>
<h1>Hello, World</h1>
<Nav />
</Header>
{children}
<Footer/>
</section>
)
is equivalent to:
const Container = ({ children, context }) => (
<section>
<Header context={context}>
<h1>Hello, World</h1>
{(headerContext) => <Nav context={headerContext} />}
</Header>
{children.withContext(context)}
<Footer context={context}/>
</section>
)
Note that HTML elements and text nodes do not interact with context.
Context is an object with the following methods:
update
: create a new context with an updated value
context.update(
key: string | symbol,
update: (previousValue) => nextValue
) => Context
get
: read a value from context, or get its default value
context.get(
key: string | symbol,
defaultValue?: any
) => any
Context can also be consumed via a `useContext` hook:
```js
const value = useContext(key, defaultValue)
Context can be provided to elements via the context
prop.
<Foo context={context}/>
If an element is not explicitly provided a context
prop, it will receive the context its parent element passes to its children.
Passing a non-Context value as a context
prop is an error.
Children is an object with the following methods:
withContext
: create a new children object with an updated context
children.withContext(Context) => Children
Calling withContext
with a non-Context value is an error.
Regardless of what type of value is passed as the children prop, the component will always receive an opaque Children
object.
If a function is used in children
, that function is called with the parent context as its argument:
<Container>
{(context) => <Foo value={context.use(key)} />}
</Container>
function createContext (defaultValue) {
const key = Symbol()
// <Context.Provider value={value}>{...}</Provider>
const Provider = ({ value, children, context }) =>
children.withContext(context.update(key, () => value))
// <Context.Consumer render={(value) => ...} />
const Consumer = ({ render, context }) =>
render(context.get(key, defaultValue))
// const value = Context.use()
function use () {
return useContext(key, defaultValue)
}
return { use, Provider, Consumer }
}