@xstate/store-react
The @xstate/store-react package provides React bindings for XState Store. It includes hooks for subscribing to store state, creating component-scoped stores, and using atoms.
These are the docs for @xstate/store-react v2. For v1 docs, see v1 docs.
This package re-exports all of @xstate/store, so you only need to install @xstate/store-react.
Installation
npm install @xstate/store-reactpnpm install @xstate/store-reactyarn add @xstate/store-reactQuick start
import { createStore, useSelector } from '@xstate/store-react';
const store = createStore({
context: { count: 0 },
on: {
inc: (context, event: { by?: number }) => ({
count: context.count + (event.by ?? 1),
}),
},
});
function Counter() {
const count = useSelector(store, (state) => state.context.count);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => store.trigger.inc()}>+1</button>
<button onClick={() => store.trigger.inc({ by: 5 })}>+5</button>
</div>
);
}API
useSelector(store, selector?, compare?)
Subscribes to a store or atom and returns a selected value. The component re-renders when the selected value changes.
import { useSelector } from '@xstate/store-react';
function Counter() {
const count = useSelector(store, (state) => state.context.count);
const user = useSelector(
store,
(state) => state.context.user,
(prev, next) => prev.id === next.id
);
return <div>Count: {count}</div>;
}Parameters:
store- The store or atom to subscribe toselector- Optional function to select a valuecompare- Optional comparison function (defaults to strict equality===)
Returns: The selected value
useStore(configOrLogic, input?)
Creates a component-scoped store instance. Pass either a store config or store logic created with createStoreLogic(...).
import { createStoreLogic, useSelector, useStore } from '@xstate/store-react';
const counterLogic = createStoreLogic({
context: (input: { initialCount: number }) => ({
count: input.initialCount,
}),
on: {
inc: (context) => ({ count: context.count + 1 }),
dec: (context) => ({ count: context.count - 1 }),
},
});
function Counter() {
const store = useStore(counterLogic, { initialCount: 0 });
const count = useSelector(store, (state) => state.context.count);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => store.trigger.inc()}>+</button>
<button onClick={() => store.trigger.dec()}>-</button>
</div>
);
}If the store logic requires input, the input argument is required. If the input is optional, useStore(logic) is allowed.
Parameters:
configOrLogic- Store configuration object or store logicinput- Optional or required input for store logic
Returns: A store instance, stable across re-renders
useAtom(atomOrConfig, selectorOrInput?, compare?)
Subscribes to an atom and returns its value. You can pass an existing atom, or an atom config created with createAtomConfig(...).
import { createAtom, useAtom } from '@xstate/store-react';
const countAtom = createAtom(0);
function Counter() {
const count = useAtom(countAtom);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => countAtom.set((prev) => prev + 1)}>+</button>
</div>
);
}With an atom config:
import { createAtomConfig, useAtom } from '@xstate/store-react';
const countConfig = createAtomConfig((input: { initialCount: number }) => {
return input.initialCount;
});
function Counter() {
const count = useAtom(countConfig, { initialCount: 0 });
return <div>Count: {count}</div>;
}Parameters:
atomOrConfig- Existing atom or atom configselectorOrInput- Selector for existing atoms, or input for atom configscompare- Optional comparison function for existing atoms
Returns: The selected atom value
useAtomState(atomOrConfig, input?)
Creates or subscribes to an atom for the lifetime of a React component. It returns the current value and the live atom instance.
import { createAtomConfig, useAtomState } from '@xstate/store-react';
const countConfig = createAtomConfig((input: { initialCount: number }) => {
return input.initialCount;
});
function Counter() {
const [count, countAtom] = useAtomState(countConfig, { initialCount: 0 });
return (
<button onClick={() => countAtom.set((count) => count + 1)}>
{count}
</button>
);
}Parameters:
atomOrConfig- Existing atom or atom configinput- Optional or required input for atom configs
Returns: [value, atom]
createStoreHook(config)
Creates a custom React hook that combines useSelector() with a store created from a config object.
import { createStoreHook } from '@xstate/store-react';
const useCountStore = createStoreHook({
context: { count: 0 },
on: {
inc: (ctx, event: { by: number }) => ({
count: ctx.count + event.by,
}),
},
});
function Counter() {
const [count, store] = useCountStore((s) => s.context.count);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => store.trigger.inc({ by: 1 })}>+1</button>
</div>
);
}Parameters:
config- Store configuration object
Returns: A custom hook that returns [selectedValue, store]
Full documentation
For complete XState Store documentation including context, transitions, effects, atoms, and more, see the XState Store docs.