Batched updates for shared slices
In the official Zustand docs, they show an example of "shared" slices, where you can access other slices and create composite actions.
const createSharedSlice: StateCreator<
BearSlice & FishSlice,
[],
[],
SharedSlice
> = (set, get) => ({
addBoth: () => {
// you can reuse previous methods
get().addBear()
get().addFish()
// or do them from scratch
// set((state) => ({ bears: state.bears + 1, fishes: state.fishes + 1 })
},
getBoth: () => get().bears + get().fishes,
})
While the Zundo docs do show an example of the slices pattern, it does not mention the shared slices functionality. Of course, if state is set twice, this will push two states on the undo stack, rather than just one.
What would be the ideal way to 'batch' updates together, such that they are grouped as a single update? It doesn't seem possible to use the pause/resume functionality for this, as this is on the slice level, before the store is created.
I have created a playground which illustrates the problem.
Once way of working around the problem has been to create a leading debounce function (one that only executes the first call within a given time window), and using that with handleSet.
type AnyFunction = (...args: any[]) => any;
function debounce<T extends AnyFunction>(func: T, wait: number): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout> | undefined;
let hasExecuted = false;
return function (...args: Parameters<T>) {
if (!hasExecuted) {
func(...args);
hasExecuted = true;
}
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
hasExecuted = false;
}, wait);
};
}
This works, but it doesn't seem ideal - are there any other solutions to this problem?