Scoped state with createContext
Give each part of the tree its own store with the same selector and action API as global state.
Provider A
name: “Ada”
name: “Ada”
Provider B
name: “Grace”
name: “Grace”
Same component. Independent store instances.
The problem this solves
A form, a wizard or a list row needs state that several components share, but that must not leak to the rest
of the app or to another instance of itself. createContext creates a store per Provider.
Create and use a context
counter-context.tsx
import { createContext } from 'react-global-state-hooks';
export const CounterContext = createContext(
{ count: 0 },
{
actions: {
increment(by = 1) {
return ({ setState }) => {
setState((state) => ({ count: state.count + by }));
};
},
},
},
);
export function Counter({ label }: { label: string }) {
// Reads the closest CounterContext.Provider above this component.
const [count, actions] = CounterContext.use((state) => state.count);
return (
<button onClick={() => actions.increment()}>
{label}: {count}
</button>
);
}
export function TwoCounters() {
// Each Provider creates its own independent store.
return (
<>
<CounterContext.Provider>
<Counter label="left" />
</CounterContext.Provider>
<CounterContext.Provider value={{ count: 10 }}>
<Counter label="right" />
</CounterContext.Provider>
</>
);
}createContext(initialState, options?) returns { use, Provider, Context }. It supports the same options as a
global store except persistence: actions, metadata, name and callbacks.
Provider values
| Provider prop | Result |
|---|---|
| none | The store starts from the context’s initial state. |
value={x} | The store starts from x, and follows x when it changes. |
value={(initial) => ...} | The function runs once to create the initial state. It receives the context’s initial state, not the value of a parent provider. |
Reading from a context
| Call | Returns |
|---|---|
Ctx.use(selector?, deps?) | The same tuple as a store hook. |
Ctx.use.select(selector) | Just the selected value. |
Ctx.use.api() | The store API for the closest provider (getState, setState, subscribe, …). |
Ctx.use.actions() | The closest provider’s actions object. |
Ctx.use.observable(selector) | A memoised observable for the closest provider. |
Ctx.use.createSelectorHook(selector) | A shared, chainable selector hook for this context. |
Ctx.use throws use hook must be used within a ContextProvider when there is no provider above it.
Lifecycle callbacks
Set callbacks on the context or onCreated / onMounted on a single Provider. onMounted may return a
cleanup function that runs on unmount.
What to watch for
- Each mounted
Provideris a new store. Remounting a provider resets its state. - Persistence to
localStorageis a feature of global stores, not of contexts.