Zustand Computed State Middleware

2.1.2 · active · verified Wed Apr 22

Zustand-computed is a lightweight, TypeScript-friendly middleware designed for the Zustand state management library, enabling the creation of derived or 'computed' state based on the existing store state. The current stable version is 2.1.2, released in April 2026. The package maintains an active release cadence, with multiple bug fixes and minor features released within the last year, demonstrating ongoing development and support. Its primary differentiator is its simplicity and direct integration with Zustand's middleware pattern, providing a straightforward way to add calculated properties to a store without manual memoization or complex selectors. It focuses on functional transformations and offers options to optimize recomputation with `keys` or a `shouldRecompute` function, differentiating it from purely selector-based approaches by integrating computed values directly into the store's state tree.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to define a Zustand store with computed state using `createComputed`, including TypeScript types, and basic state manipulation. It shows how the computed property (`countSq`) becomes part of the store's observable state and is accessible like any other state property.

import { create } from 'zustand'
import { createComputed } from 'zustand-computed'

type Store = {
  count: number
  inc: () => void
  dec: () => void
}

type ComputedStore = {
  countSq: number
}

const computed = createComputed((state: Store): ComputedStore => ({
  countSq: state.count ** 2,
}))

// To integrate with other middleware like devtools or immer, wrap them around computed
// For example: create<Store>()(devtools(computed(...))) or create<Store>()(immer(computed(...)))

const useStore = create<Store>()(
  computed(
    (set, get) => ({
      count: 1,
      inc: () => set((state) => ({ count: state.count + 1 })),
      dec: () => set((state) => ({ count: state.count - 1 })),
      // get() function inside the store definition has access to both base and computed state
      square: () => set(() => ({ count: get().countSq })),
      root: () => set((state) => ({ count: Math.floor(Math.sqrt(state.count)) })),
    })
  )
)

// Example usage (e.g., in a React component)
function Counter() {
  const { count, countSq, inc, dec } = useStore()
  return (
    <div>
      <span>Count: {count}</span>
      <br />
      <span>Count Squared: {countSq}</span>
      <br />
      <button onClick={inc}>+1</button>
      <button onClick={dec}>-1</button>
    </div>
  )
}

// To demonstrate outside React, for example in Node.js:
const unsubscribe = useStore.subscribe((state) => {
  console.log('Current state:', state.count, 'Computed:', state.countSq);
});

useStore.getState().inc(); // Increment count, triggering recomputation
useStore.getState().inc();

unsubscribe();

view raw JSON →