Contexts
Because component functions return plain DOM elements, you cannot call methods
on them after they are created. To let components interact, domstatejsx
attaches contexts to the DOM itself. We will look at two scenarios:
- A child component wants to invoke an action on a parent component (upwards)
- A parent component wants to invoke an action on a child component (downwards)
Upwards, with callbacks
Section titled “Upwards, with callbacks”The simplest way to interact with a parent is to pass a callback as a prop:
export default function App() { const refs = useRefProxy(); const [, setCount] = useIntContent(refs.span);
function increment() { setCount((prev) => prev + 1); }
return ( <> <span ref={refs.span}>0</span> <ButtonContainer onClick={increment} /> </> );}
function ButtonContainer({ onClick }) { return <button onClick={onClick}>Click me</button>;}Upwards, with context lookup
Section titled “Upwards, with context lookup”Alternatively, a parent can expose its functionality through context, and a child can look it up by walking up the DOM tree.
export default function App() { const refs = useRefProxy(); const [, setCount] = useIntContent(refs.span);
function increment() { setCount((prev) => prev + 1); }
return ( <App.Context.Provider value={{ increment }}> <span ref={refs.span}>0</span> <ButtonContainer /> </App.Context.Provider> );}App.Context = createContext();
function ButtonContainer() { const refs = useRefProxy();
function handleClick() { const { increment } = useContextUp(refs.head.current, App.Context); increment(); }
return <button onClick={handleClick} ref={refs.head}>Click me</button>;}The context is attached to the DOM. useContextUp uses a DOM element as the
starting point and walks up until it finds a node with an App.Context
associated with it, then returns its value.
Downwards, accessing context through a ref
Section titled “Downwards, accessing context through a ref”To let a parent call methods on a child, the child exposes its functionality
through context, and the parent attaches a ref to the child component. The
ref’s .context property contains all the contexts that were attached to that
element:
function Counter() { const refs = useRefProxy(); const [, setSpan] = useIntContent(refs.span);
function increment() { setSpan((prev) => prev + 1); }
return ( <Counter.Context.Provider value={{ increment }}> <span ref={refs.span}>0</span> </Counter.Context.Provider> );}Counter.Context = createContext();
export default function App() { const refs = useRefProxy();
function handleClick() { refs.counter.context.increment(); }
return ( <> <Counter ref={refs.counter} /> <button onClick={handleClick}>Click me</button> </> );}Downwards, with context lookup
Section titled “Downwards, with context lookup”To affect many child components at once, search for context downwards:
export default function App() { const refs = useRefProxy();
function handleClick() { useContextDown(refs.head.current, Counter.Context).forEach( ({ increment }) => increment(), ); }
return ( <div ref={refs.head}> <Counter /> <Counter /> <Counter /> <button onClick={handleClick}>Click me</button> </div> );}useContextDown searches the DOM under the starting node and returns a list of
all matching contexts.
Context API
Section titled “Context API”createContext(defaultValue?)
Section titled “createContext(defaultValue?)”Creates a new context object.
Context.Provider
Section titled “Context.Provider”A component that receives a value and attaches it to the DOM so that it can
be found by context lookups. It must wrap a single element — wrapping a
fragment-returning component throws an error.
<App.Context.Provider value={{ increment }}> <div>...</div></App.Context.Provider>useContextUp(node, context)
Section titled “useContextUp(node, context)”Walks up from node looking for a provider for context. Returns the value or
null.
useContextDown(node, context)
Section titled “useContextDown(node, context)”Searches the subtree under node for providers for context. Returns a list
of values.
useContextSide(node, context, upContext)
Section titled “useContextSide(node, context, upContext)”First walks up from node until it finds a provider for upContext, then
searches downwards from there for providers for context. Useful for reaching
“sibling” components: find the common ancestor first, then search its children.
findUp(node, context)
Section titled “findUp(node, context)”Like useContextUp but returns the provider’s DOM element (or null) instead
of its value.