Notification semantics
This page describes the precise notification behavior implied by store/src/index.ts.
Update pipeline
When you call setState(nextState), the store builds a dispatch chain from the current middleware list. The list is copied with [...this.middlewares] for that call, then reduced with reduceRight so array order defines outer-to-inner middleware order.
The final dispatch calls applyState().
State resolution
applyState() stores prevState, resolves a function updater with prevState, or uses the provided value as-is.
const resolvedState =
typeof nextState === "function"
? nextState(prevState)
: nextState;Then it compares prevState and resolvedState with Object.is.
No-notify cases
The store does not notify when:
- the updater returns the previous value,
- an object or array is mutated in place and the same reference is returned,
- a middleware blocks the update by not calling
next(), - a middleware transforms the update into the previous value.
For primitives, Object.is follows JavaScript semantics: Object.is(NaN, NaN) is true, and Object.is(0, -0) is false.
Listener iteration
When notification happens, the store iterates over Array.from(this.listeners). This makes a snapshot of the listeners for that notification pass.
Consequences:
- a listener added during notification waits until a later update,
- a listener removed during notification may still run in the current pass if it was already in the snapshot,
- listener order follows
Setinsertion order for the snapshot.
Reentrant updates
A listener can call setState() again because the implementation does not block reentrancy. This can be useful for derived state but can also create loops. Add explicit guards if you intentionally update from a listener.
Error propagation
Middleware, updater functions, and listeners run synchronously and errors are not caught by the store. A thrown error leaves responsibility with the caller and can stop the current pipeline.