Releases: pmndrs/zustand
v3.2.0
This release improves scoped subscription api (subscription with selector).
[BREAKING CHANGE]
This includes a breaking change in undocumented api and behavior.
Pre-v3.2:
const store = create(...)
store.subscribe((foo, error) => {
...
}, state => state.foo)
// errors in the selector are caught and passed as the second argument of the listener.
v3.2:
const store = create(...)
store.subscribe((foo, prevFoo) => {
...
}, state => state.foo)
// the second argument of the listener is previous value and errors in the selector are not caught.
v3.1.4
v3.1.3
v3.1.2
v3.1.1
v3.1.0
This release is mainly for TypeScript users.
The base State
type is stricter.
See also:
New combine
middleware
This will combine two parts of state into one. The first part is primitive state, and the second part is actions that depend on set
.
The resulting type is inferred from the state creator.
v3.0.3
v3.0.2
Zustand 3.x
What's new
First of all, this release is 100% backward compatible, it will not break your code! The only breaking change (the create functions return value) still can work in the old way, but throws a small deprecation warning.
Our main focus has been:
- Stability and fixing bugs
- Making it suitable for concurrent mode
- Supporting React-fast-refresh
- Making it more versatile so that it can be used without React
We will soon publish an experimental V4 that utilizes react-experimentals useMutableSource in concurrent mode. The groundwork for this has been laid in this major.
Simpler API
import create from 'zustand'
const useStore = create(set => ({
bears: 0,
increasePopulation: () => set(state => ({ count: state.bears + 1 })),
resetPopulation: () => set({ bears: 0 })
}))
function BearCounter() {
const bears = useStore(state => state.bears)
return <h1>{bears} around here ...</h1>
}
function Controls() {
const increasePopulation = useStore(state => state.increasePopulation)
return <button onClick={increasePopulation}>one up</button>
}
Utility functions are on the hooks prototype
Sometimes you need to access the state in a non-reactive way, or act upon the store. For these cases the resulting hook has utility functions attached to its prototype.
const useStore = create(() => ({ paw: true, snout: true, fur: true }))
// Getting non-reactive fresh state
const paw = useStore.getState().paw
// Listening to all changes, fires on every change
const unsub1 = useStore.subscribe(console.log)
// Listening to selected changes, in this case when "paw" changes
const unsub2 = useStore.subscribe(console.log, state => state.paw)
// Updating state, will trigger listeners
useStore.setState({ paw: false })
// Unsubscribe listeners
unsub1()
unsub2()
// Destroying the store (removing all listeners)
useStore.destroy()
// You can of course use the hook as you always would
function Component() {
const paw = useStore(state => state.paw)
Using zustand without React
Zustands core can be imported and used without the React dependency. The only difference is that the create function does not return a hook, but the api utilities.
import create from 'zustand/vanilla'
const store = create(() => ({ ... }))
const { getState, setState, subscribe, destroy } = store
You can even consume an existing vanilla store with React:
import create from 'zustand'
import vanillaStore from './vanillaStore'
const useStore = create(vanillaStore)
Overwriting state
The set
function has a second argument, false by default. Instead of merging, it will replace the state model. Be careful not to wipe out parts you rely on, like actions.
import omit from "lodash-es/omit"
const useStore = create(set => ({
salmon: 1,
tuna: 2,
deleteEverything: () => set({ }), true), // clears the entire store, actions included
deleteTuna: () => set(state => omit(state, ['tuna']), true)
}))