{"id":15947,"library":"zustand-slices","title":"Zustand Slices Utility","description":"zustand-slices is a utility library designed to introduce an opinionated, TypeScript-friendly slice pattern for Zustand, a minimalist global state management library. As of version 0.4.0, it provides `createSlice` and `withSlices` helpers to structure Zustand stores into modular, reusable \"slices.\" This addresses the complexities often encountered when attempting to implement such patterns with strong TypeScript typing, particularly when following the official Zustand documentation's manual approach. The library is actively developed, with its primary maintainer frequently tweeting about updates and examples, suggesting a consistent, though not strictly scheduled, release cadence focusing on refinement and new features. Its key differentiator is its explicit support for type inference and clean separation of concerns within a Zustand store, leveraging immutable updates via Immer, which is a peer dependency.","status":"active","version":"0.4.0","language":"javascript","source_language":"en","source_url":"https://github.com/zustandjs/zustand-slices","tags":["javascript","react","zustand","slices","typescript"],"install":[{"cmd":"npm install zustand-slices","lang":"bash","label":"npm"},{"cmd":"yarn add zustand-slices","lang":"bash","label":"yarn"},{"cmd":"pnpm add zustand-slices","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for immutable state updates within slices, enabling a more natural mutable-like syntax in actions.","package":"immer","optional":false},{"reason":"Peer dependency for usage within React components, as Zustand stores are typically consumed via hooks in a React environment.","package":"react","optional":false},{"reason":"The core state management library that zustand-slices extends and builds upon.","package":"zustand","optional":false}],"imports":[{"note":"Primarily designed for ESM usage. CommonJS `require` might lead to bundler issues or incorrect type inference.","wrong":"const createSlice = require('zustand-slices').createSlice;","symbol":"createSlice","correct":"import { createSlice } from 'zustand-slices';"},{"note":"Used to compose multiple slices into a single Zustand store. Follows ESM conventions.","wrong":"const { withSlices } = require('zustand-slices');","symbol":"withSlices","correct":"import { withSlices } from 'zustand-slices';"},{"note":"The core `create` function comes from `zustand` itself, not `zustand-slices`. This library enhances its usage pattern.","wrong":"import { create } from 'zustand-slices';","symbol":"create","correct":"import { create } from 'zustand';"}],"quickstart":{"code":"import { create } from 'zustand';\nimport { createSlice, withSlices } from 'zustand-slices';\n\ninterface CountState {\n  count: number;\n  inc: () => void;\n  resetCount: () => void;\n}\n\ninterface TextState {\n  text: string;\n  updateText: (newText: string) => void;\n  resetText: () => void;\n}\n\nconst countSlice = createSlice<CountState>()({\n  name: 'count',\n  value: 0,\n  actions: {\n    inc: () => (prev) => prev + 1,\n    resetCount: () => () => 0,\n  },\n});\n\nconst textSlice = createSlice<TextState>()({\n  name: 'text',\n  value: 'Hello',\n  actions: {\n    updateText: (newText: string) => () => newText,\n    resetText: () => () => 'Hello',\n  },\n});\n\n// Combine slices and create the store\nconst useStore = create(withSlices(countSlice, textSlice));\n\n// Example component usage (requires React environment)\nfunction MyComponent() {\n  const count = useStore((state) => state.count);\n  const text = useStore((state) => state.text);\n  // Destructuring actions from getState() to ensure referential stability\n  const { inc, updateText, resetCount, resetText } = useStore.getState(); \n\n  return (\n    <>\n      <p>\n        Count: {count}\n        <button type=\"button\" onClick={inc}>\n          +1\n        </button>\n      </p>\n      <p>\n        <input value={text} onChange={(e) => updateText(e.target.value)} />\n      </p>\n      <p>\n        <button type=\"button\" onClick={resetCount}>\n          Reset Count\n        </button>\n        <button type=\"button\" onClick={resetText}>\n          Reset Text\n        </button>\n      </p>\n    </>\n  );\n}\n\n// To use MyComponent, render it within a React application.\n// For example, in a simple setup:\n// import React from 'react';\n// import ReactDOM from 'react-dom/client';\n// const root = ReactDOM.createRoot(document.getElementById('root'));\n// root.render(<MyComponent />);\n","lang":"typescript","description":"This quickstart demonstrates how to define individual state slices using `createSlice`, combine them into a single Zustand store with `withSlices`, and consume both state and actions within a React component. It also highlights distinct reset actions for each slice to avoid naming conflicts."},"warnings":[{"fix":"Explicitly install Immer in your project: `npm install immer` or `yarn add immer`.","message":"Immer is a required peer dependency for `zustand-slices` to function correctly with immutable updates, but it is not automatically installed. Failing to install Immer will lead to runtime errors or unexpected state mutations if slice actions expect Immer's draft mechanism.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Prefix action names (e.g., `resetCount`, `resetText`) or implement a single, combined action that dispatches to specific slice actions if a global reset is desired.","message":"When combining multiple slices with `withSlices`, be cautious of action name collisions (e.g., two slices both defining a `reset` action). The last slice combined will overwrite previous actions with the same name, leading to unexpected behavior.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Always use Immer's `draft` parameter if available, or return a new state object (e.g., `(prev) => ({ ...prev, value: newValue })`) for updates to ensure immutability.","message":"Directly mutating state within slice actions without leveraging Immer's draft mechanism (when Immer is installed) or explicitly returning a new state object can lead to un-tracked changes and inconsistent state, as Zustand expects immutable updates.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Consult the official Zustand TypeScript guide and examples for best practices. Ensure middleware is applied at the combined store level, not within individual slices, for predictable typing.","message":"TypeScript inference can sometimes be tricky with complex slice patterns and middleware in Zustand. While `zustand-slices` aims to improve this, incorrect generic types or middleware application can still lead to type errors.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Install Immer: `npm install immer` or `yarn add immer`.","cause":"The Immer peer dependency is not installed, but zustand-slices expects it for immutable state updates.","error":"TypeError: Cannot read properties of undefined (reading 'produce')"},{"fix":"Carefully review your `StateCreator` generics and ensure consistency across slices and the main store. Explicitly typing `createSlice<T>()(...)` can help guide inference.","cause":"TypeScript type inference failed, often due to incorrect generic parameters for `createSlice` or `create` when combining complex state shapes or applying middleware.","error":"TS2345: Argument of type '...' is not assignable to parameter of type 'StateCreator<...>'"},{"fix":"Verify that all slices are correctly passed to `withSlices` and that the property name matches the slice's defined state. Ensure your TypeScript configuration is strict enough to catch such issues.","cause":"The state property you are trying to access does not exist on the combined store's type, or there's a typo. This can happen if a slice was not correctly combined or if type inference missed a property.","error":"Property 'someProperty' does not exist on type '...' (when accessing state)"}],"ecosystem":"npm"}