I’ve been trying to find a way for computed values in Zustand for a while. The general recommended way is using a custom hook, according to Daishi Kato himself. The issue with this approach, however, is that your computed logic will be completely alienated from the store itself.
I just found a neat approach which seems to work: using a nested object inside the store itself, as pointed in this highly cheered comment. Below is a fully typed example:
import {create} from 'zustand'; import {combine} from 'zustand/middleware'; import {immer} from 'zustand/middleware/immer'; export interface Person { name: string; age: number; } const usePeople = create(immer( combine({ people: [] as Person[], }, (set, get) => ({ $computed: { get count(): number { return get().people.length; }, }, addNew(name: string, age: number): void { set(state => { state.people.push({name, age}); }); }, })), )); export default usePeople;
The tradeoff, as benchmarked by myself, is that this $computed
getters are not cached and will run every time the state changes, in addition to every time they are requested – which happens when the component re-renders. The ordinary custom hook approach runs only when they are requested. So, there is a performance penalty, which can be huge if the logic is too demanding.