Zustand Computed State Middleware
Zustand Computed State Middleware is a lightweight utility designed to seamlessly integrate derived or computed state into Zustand stores. It enables developers to define functions that calculate new state values based on the existing store state, automatically merging these computed values back into the primary store. This allows computed properties to be accessed directly alongside regular state, simplifying state management logic. The current stable version of this specific middleware is 0.1.3, representing an initial release focused on core functionality and ease of use. However, a different package with similar functionality, `zustand-computed`, is at version 2.1.1 and has seen more active development and breaking changes. As a middleware, its release cadence will likely follow its parent library, Zustand, or be driven by feature enhancements and bug fixes. A key differentiator is its 'dead simple' approach, providing direct state augmentation without the need for manual selectors in many cases, though it explicitly advises keeping computed functions light due to their re-evaluation on every state change to prevent performance bottlenecks. It ships with full TypeScript support, requiring explicit type definitions for robust usage.
Common errors
-
TypeError: (0 , zustand__WEBPACK_IMPORTED_MODULE_0__.create) is not a function
cause This typically occurs due to incorrect module import of `create` from 'zustand', often stemming from CommonJS/ESM interop issues or version differences in Zustand.fixEnsure you are using the named import `import { create } from 'zustand'` for modern Zustand versions. If you are in a CommonJS environment, check your bundler configuration to correctly handle ESM modules. -
Property 'someComputedValue' does not exist on type 'BaseStoreType'.
cause In TypeScript, this error indicates that the type of your store (`BaseStoreType` in this example) does not include the computed properties. The combined store type, including computed state, needs to be explicitly used.fixDefine a `CombinedStore` type that merges your base store and computed store types (e.g., `type CombinedStore = BaseStore & ComputedStore;`). Then, pass this `CombinedStore` type as a generic to Zustand's `create` function: `create<CombinedStore>(...)`.
Warnings
- gotcha Computed values are re-evaluated on every state change. To prevent performance bottlenecks, ensure that computed functions are kept lightweight and perform minimal computations.
- gotcha When using TypeScript, explicit and correct type declarations are crucial for the base store, computed store, and their combined type to ensure full type safety throughout your application.
- deprecated The original `zustand-middleware-computed-state` package seems to have been less actively maintained since its initial release. A package with a similar name, `zustand-computed`, has actively developed and introduced a breaking change in v2.0.0, replacing the `computed` middleware with a `createComputed` function.
Install
-
npm install zustand-middleware-computed-state -
yarn add zustand-middleware-computed-state -
pnpm add zustand-middleware-computed-state
Imports
- computed
const { computed } = require('zustand-middleware-computed-state')import { computed } from 'zustand-middleware-computed-state' - create
import create from 'zustand'
import { create } from 'zustand' - StateCreator
import { StateCreator } from 'zustand'import type { StateCreator } from 'zustand'
Quickstart
import create from 'zustand';
import { computed } from 'zustand-middleware-computed-state';
import React from 'react';
import ReactDOM from 'react-dom/client';
const useStore = create(
computed(
(set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}),
(state) => {
function isEnough() {
if (state.count > 100) {
return 'Is enough';
} else {
return 'Is not enough';
}
}
return {
computedCount: state.count + 10,
isEnough: isEnough(),
};
}
)
);
function Counter() {
const { count, computedCount, isEnough, inc } = useStore();
return (
<div>
<button onClick={inc}>Increment</button>
<div>count: {count}</div>
<div>computedCount: {computedCount}</div>
<div>isEnough: {isEnough}</div>
</div>
);
}
// Render the Counter component to a DOM element
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Counter />);