Map and Set Usage
Map and Set are mutable data structures. To use them in Zustand, you must create new instances when updating.
Map
Reading a Map
const foo = useSomeStore((state) => state.foo)
Updating a Map
Always create a new Map instance:
// Update single entry
set((state) => ({
foo: new Map(state.foo).set(key, value),
}))
// Delete entry
set((state) => {
const next = new Map(state.foo)
next.delete(key)
return { foo: next }
})
// Update multiple entries
set((state) => {
const next = new Map(state.foo)
next.set('key1', 'value1')
next.set('key2', 'value2')
return { foo: next }
})
// Clear
set({ foo: new Map() })
Set
Reading a Set
const bar = useSomeStore((state) => state.bar)
Updating a Set
Always create a new Set instance:
// Add item
set((state) => ({
bar: new Set(state.bar).add(item),
}))
// Delete item
set((state) => {
const next = new Set(state.bar)
next.delete(item)
return { bar: next }
})
// Toggle item
set((state) => {
const next = new Set(state.bar)
next.has(item) ? next.delete(item) : next.add(item)
return { bar: next }
})
// Clear
set({ bar: new Set() })
Why New Instances?
Zustand detects changes by comparing references. Mutating a Map or Set doesn't change its reference:
// ❌ Wrong - same reference, no re-render
set((state) => {
state.foo.set(key, value)
return { foo: state.foo }
})
// ✅ Correct - new reference, triggers re-render
set((state) => ({
foo: new Map(state.foo).set(key, value),
}))
Pitfall: Type Hints for Empty Collections
Provide type hints when initializing empty Maps and Sets:
{
ids: new Set([] as string[]),
users: new Map([] as [string, User][])
}
Without type hints, TypeScript infers never[] which prevents adding items later.