useMultipleStore
Reads several store instances in one call. The refs come from storeRef(params), of one store or of several, and their number may change from one render to the next, so a component can read one instance per item of a list.
import { useMultipleStore } from 'react-state-custom'
function useMultipleStore<const Refs extends readonly StoreRef[]>(
refs: Refs,
options?: { schedule?: Scheduler }
): StatesOf<Refs> // one StoreState per ref, in order
function useMultipleStore<const Refs extends readonly StoreRef[], R>(
refs: Refs,
options: { select: (states: StatesOf<Refs>) => R, isEqual?: (a: R, b: R) => boolean, schedule?: Scheduler }
): REach instance starts, is shared and stops as it would with useStore: one call reading ten refs counts as ten readers. When the list changes, the instances that join start and the ones that leave stop after their timeToClean.
Proxies
Without select, it returns one tracking proxy per ref, in the order of refs, like useStore(params) returns for each. The component re-renders for the keys it read from any of them.
const { storeRef: roomRef } = createStore('room', useRoom)
function RoomTabs({ roomIds }: { roomIds: string[] }) {
const rooms = useMultipleStore(roomIds.map(id => roomRef({ id })))
return <>{rooms.map((room, i) => <Tab key={roomIds[i]} name={roomIds[i]} unread={room.unread ?? 0} />)}</>
}A tuple of refs is typed by position:
const [user, cart] = useMultipleStore([userRef(), cartRef({ id })])
user.name // string | undefined, from the user store
cart.items // Item[] | undefined, from the cart storeselect
With select, it returns select(states) over the plain states, in the order of refs, and re-renders only when that value changes. isEqual defaults to a shallow comparison (Object.is one level deep), so a fresh array with the same items is no change.
// renders when the total changes, not on every message of every room
const unread = useMultipleStore(roomIds.map(id => roomRef({ id })), {
select: rooms => rooms.reduce((sum, room) => sum + (room.unread ?? 0), 0),
})select runs whenever any of the instances changes. A call site must pass select on every render or on none, as with useStore.
Options
schedule: when the component re-renders for a change, for every instance. By default each instance follows its store'sscheduleoption. See Update cadence.select,isEqual: see above.
Notes
- Inside a store hook it works as in a component: a store can read a list of instances, for example a summary over the per-id stores of a collection.
- Before an instance has run, its state is
{}, as withuseStore. On the server every state is{}, and nothing runs. - The refs may be new objects on every render: instances are matched by name and params, not by the identity of the ref.
- A failed instance: the component throws the error of the first instance whose store hook threw, for its error boundary, as
useStoredoes. See Error handling. - Not a ref: an item that
storeRefdid not make throws aTypeErrornaming its index.
See Rendering a list for when to give each item a store of its own and when to keep a collection in one store.