Store & Provider Boundary
Use a scope for local state. Use a store when state should be shared through a React subtree or owned by a domain.
createStore(name, setup) returns a tuple:
| Tuple item | Use |
|---|---|
useStore | Read the store inside React components |
getStore | Access the store inside another store setup or a scope factory |
Basic Store
Section titled “Basic Store”import { createStore, observable, StoreProvider } from "@usels/core";
const [useCartStore, getCartStore] = createStore("cart", () => { const items$ = observable<Record<string, number>>({}); const count$ = observable(() => Object.values(items$.get()).reduce((total, quantity) => total + quantity, 0) );
const addItem = (id: string) => { items$.set((items) => ({ ...items, [id]: (items[id] ?? 0) + 1 })); };
return { items$, count$, addItem };});
function App() { return ( <StoreProvider> <CartButton /> </StoreProvider> );}
function CartButton() { const { count$, addItem } = useCartStore();
return <button onClick={() => addItem("keyboard")}>Cart {count$.get()}</button>;}Provider Boundary
Section titled “Provider Boundary”StoreProvider owns the store registry for its subtree. That boundary matters
for SSR requests, tests, embedded roots, and app shells because every provider
gets isolated store instances.
Use getStore() inside another store setup function or inside a "use scope"
factory rendered under a provider:
function StoreBackedSearch() { "use scope";
const { setQuery } = getSearchStore(); const draft$ = observable("");
observe(() => { setQuery(draft$.get()); });
return <input value={draft$.get()} onChange={(event) => draft$.set(event.currentTarget.value)} />;}