Implement global state management in React apps using TanStack Store (@tanstack/react-store). Use when creating stores, derived state, subscriptions, batched updates, or integrating TanStack Store with React components via the useStore hook. Covers createStore, useStore, shallow comparison, batch, derived stores, atoms, and async atoms.
Resources
1Install
npx skillscat add fellipeutaka/leon/tanstack-react-store Install via the SkillsCat registry.
TanStack React Store
Framework-agnostic reactive data store with a React adapter. Install @tanstack/react-store.
Core API
createStore
Create a writable store with an initial value, or a readonly derived store with a getter function.
import { createStore } from "@tanstack/react-store";
// Writable store
const countStore = createStore(0);
countStore.setState(() => 1);
console.log(countStore.state); // 1
// Object store
const appStore = createStore({ dogs: 0, cats: 0 });
// Derived (readonly) store — auto-updates when dependencies change
const doubled = createStore(() => countStore.state * 2);Store class
store.state/store.get()— read current valuestore.setState((prev) => next)— update with updater fn (not available on derived/readonly stores)store.subscribe((value) => void)— listen to changes, returns{ unsubscribe }
Derived stores — previous value
Access the previous derived value via the prev argument:
const sum = createStore<number>((prev) => count.state + (prev ?? 0));batch
Batch multiple setState calls; subscribers fire once at the end:
import { batch } from "@tanstack/react-store";
batch(() => {
countStore.setState(() => 1);
countStore.setState(() => 2);
});React Integration
useStore
Subscribe a React component to a store. Accepts a selector for fine-grained re-renders.
import { createStore, useStore } from "@tanstack/react-store";
const store = createStore({ dogs: 0, cats: 0 });
function Display({ animal }: { animal: "dogs" | "cats" }) {
// Only re-renders when state[animal] changes
const count = useStore(store, (state) => state[animal]);
return <div>{`${animal}: ${count}`}</div>;
}Signature:
function useStore<TAtom extends AnyAtom | undefined, T>(
atom: TAtom,
selector: (snapshot: AtomState) => T,
compare?: (a: T, b: T) => boolean,
): T;atom— store or atom instanceselector— derive the slice of state needed (keeps re-renders minimal)compare— optional custom equality check (default:Object.is)
shallow
Use shallow as the compare function when selecting objects/arrays to avoid unnecessary re-renders:
import { useStore, shallow } from "@tanstack/react-store";
const items = useStore(store, (s) => s.items, shallow);Updating state from event handlers
Call setState outside of React — no hooks needed:
const updateState = (animal: string) => {
store.setState((state) => ({
...state,
[animal]: state[animal] + 1,
}));
};Best Practices
- Define stores outside components — stores are singletons; instantiate at module level.
- Use selectors — always pass a selector to
useStoreto avoid full-state re-renders. - Use
shallow— when selecting objects/arrays, passshallowas the compare fn. - Batch related updates — wrap multiple
setStatecalls inbatch()to notify subscribers once. - Prefer derived stores over manual sync — use
createStore(() => ...)for computed values instead of manually keeping stores in sync. - Immutable updates —
setStateupdater must return a new reference (spread objects/arrays). - Cleanup subscriptions — call
unsubscribe()returned bystore.subscribe()when done.
API Reference
For detailed type signatures and advanced APIs (atoms, async atoms, observers), see references/api-reference.md.