Token导航 LogoToken导航

Agent Skill · 研究检索

zustand-middleware(zustand 中间件)

zustand-middleware 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

zustand-middleware 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证为 MIT,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 46,467。

总安装 776周安装 33GitHub Stars 143下载 272核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:zustand-middleware(zustand 中间件)
来源仓库:https://github.com/thebushidocollective/han
仓库路径:skills/zustand-middleware
安装命令:
npx skills add https://github.com/thebushidocollective/han --skill zustand-middleware
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/thebushidocollective/han --skill zustand-middleware

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

zustand-middleware 用于查找、检索和筛选相关信息。适合在 Codex、Claude、Cursor、Gemini CLI 中根据关键词或任务场景快速定位候选结果。通过 npx skills add 命令从指定 GitHub 仓库安装使用。

安装前需确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。建议结合原始 README 核验具体用法和功能边界。

来源仓库内路径:skills/zustand-middleware

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/thebushidocollective/han --skill zustand-middl…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

zustand-middleware 怎么安装?

在终端执行 npx skills add https://github.com/thebushidocollective/han --skill zustand-middleware。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

zustand-middleware 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

zustand-middleware 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

zustand-middleware 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

zustand-middleware 用的人多吗?

公开数据是累计安装 776 次,近一周安装 33 次,下载 272 次,GitHub 143 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

zustand-middleware 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
zustand-middleware

zustand 中间件 · 本页

776143需要联网MIT通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Zustand - Middleware

Zustand provides powerful middleware to enhance store functionality including persistence, Redux DevTools integration, immutable updates with Immer, and more.

Key Concepts

Middleware Composition

Middleware wraps the store creator function:

import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'

const useStore = create(
  devtools(
    persist(
      (set) => ({
        count: 0,
        increment: () => set((state) => ({ count: state.count + 1 })),
      }),
      { name: 'counter-storage' }
    )
  )
)

Order Matters

Apply middleware from inside out:

// ✅ Correct order
create(devtools(persist(immer(...))))

// devtools wraps persist wraps immer wraps your store

Best Practices

1. Persist Middleware

Save and restore store state to localStorage or other storage:

import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

interface CartStore {
  items: CartItem[]
  addItem: (item: CartItem) => void
  removeItem: (id: string) => void
  clearCart: () => void
}

const useCartStore = create<CartStore>()(
  persist(
    (set) => ({
      items: [],
      addItem: (item) =>
        set((state) => ({ items: [...state.items, item] })),
      removeItem: (id) =>
        set((state) => ({
          items: state.items.filter((item) => item.id !== id),
        })),
      clearCart: () => set({ items: [] }),
    }),
    {
      name: 'shopping-cart',
      storage: createJSONStorage(() => localStorage),
    }
  )
)
Persist Options
persist(
  (set) => ({ /* store */ }),
  {
    name: 'my-store', // unique name for storage key
    storage: createJSONStorage(() => localStorage), // or sessionStorage
    partialize: (state) => ({ count: state.count }), // only persist specific fields
    onRehydrateStorage: (state) => {
      console.log('hydration starts')
      return (state, error) => {
        if (error) {
          console.log('error during hydration', error)
        } else {
          console.log('hydration finished')
        }
      }
    },
    version: 1,
    migrate: (persistedState, version) => {
      // Handle version migrations
      if (version === 0) {
        // migrate old state to new format
      }
      return persistedState
    },
  }
)

2. DevTools Middleware

Integrate with Redux DevTools for debugging:

import { create } from 'zustand'
import { devtools } from 'zustand/middleware'

interface Store {
  count: number
  increment: () => void
  decrement: () => void
}

const useStore = create<Store>()(
  devtools(
    (set) => ({
      count: 0,
      increment: () =>
        set((state) => ({ count: state.count + 1 }), false, 'increment'),
      decrement: () =>
        set((state) => ({ count: state.count - 1 }), false, 'decrement'),
    }),
    { name: 'CounterStore' }
  )
)
DevTools Options
devtools(
  (set) => ({ /* store */ }),
  {
    name: 'MyStore', // name in devtools
    enabled: process.env.NODE_ENV === 'development', // enable conditionally
    anonymousActionType: 'action', // default action name
    trace: true, // include stack traces
  }
)

3. Immer Middleware

Write immutable updates with mutable syntax:

import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'

interface TodoStore {
  todos: Todo[]
  addTodo: (text: string) => void
  toggleTodo: (id: string) => void
  updateTodo: (id: string, text: string) => void
}

const useTodoStore = create<TodoStore>()(
  immer((set) => ({
    todos: [],

    addTodo: (text) =>
      set((state) => {
        state.todos.push({
          id: Date.now().toString(),
          text,
          completed: false,
        })
      }),

    toggleTodo: (id) =>
      set((state) => {
        const todo = state.todos.find((t) => t.id === id)
        if (todo) {
          todo.completed = !todo.completed
        }
      }),

    updateTodo: (id, text) =>
      set((state) => {
        const todo = state.todos.find((t) => t.id === id)
        if (todo) {
          todo.text = text
        }
      }),
  }))
)

4. Subscriptions

Listen to state changes outside React:

const useStore = create<Store>()((set) => ({ /* ... */ }))

// Subscribe to all changes
const unsubscribe = useStore.subscribe((state, prevState) => {
  console.log('State changed:', state)
})

// Subscribe to specific values
const unsubscribe = useStore.subscribe(
  (state) => state.count,
  (count, prevCount) => {
    console.log('Count changed from', prevCount, 'to', count)
  }
)

// Clean up
unsubscribe()

5. Combining Multiple Middleware

import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
import { immer } from 'zustand/middleware/immer'

interface Store {
  count: number
  todos: Todo[]
  increment: () => void
  addTodo: (text: string) => void
}

const useStore = create<Store>()(
  devtools(
    persist(
      immer((set) => ({
        count: 0,
        todos: [],

        increment: () =>
          set((state) => {
            state.count++
          }),

        addTodo: (text) =>
          set((state) => {
            state.todos.push({
              id: Date.now().toString(),
              text,
              completed: false,
            })
          }),
      })),
      {
        name: 'app-storage',
        partialize: (state) => ({
          count: state.count,
          todos: state.todos,
        }),
      }
    ),
    { name: 'AppStore' }
  )
)

Examples

Custom Logging Middleware

import { StateCreator, StoreMutatorIdentifier } from 'zustand'

type Logger = <
  T,
  Mps extends [StoreMutatorIdentifier, unknown][] = [],
  Mcs extends [StoreMutatorIdentifier, unknown][] = []
>(
  f: StateCreator<T, Mps, Mcs>,
  name?: string
) => StateCreator<T, Mps, Mcs>

type LoggerImpl = <T>(
  f: StateCreator<T, [], []>,
  name?: string
) => StateCreator<T, [], []>

const loggerImpl: LoggerImpl = (f, name) => (set, get, store) => {
  const loggedSet: typeof set = (...a) => {
    set(...a)
    console.log(...(name ? [`${name}:`] : []), get())
  }

  store.setState = loggedSet

  return f(loggedSet, get, store)
}

export const logger = loggerImpl as unknown as Logger

// Usage
const useStore = create<Store>()(
  logger(
    (set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
    }),
    'CounterStore'
  )
)

Custom Reset Middleware

import { StateCreator, StoreMutatorIdentifier } from 'zustand'

type Resettable = <
  T,
  Mps extends [StoreMutatorIdentifier, unknown][] = [],
  Mcs extends [StoreMutatorIdentifier, unknown][] = []
>(
  f: StateCreator<T, Mps, Mcs>
) => StateCreator<T, Mps, Mcs>

type ResettableImpl = <T>(
  f: StateCreator<T, [], []>
) => StateCreator<T, [], []>

const resettableImpl: ResettableImpl = (f) => (set, get, store) => {
  const initialState = f(set, get, store)

  store.reset = () => set(initialState)

  return initialState
}

export const resettable = resettableImpl as unknown as Resettable

// Extend store type
declare module 'zustand' {
  interface StoreApi<T> {
    reset?: () => void
  }
}

// Usage
const useStore = create<Store>()(
  resettable((set) => ({
    count: 0,
    name: '',
    increment: () => set((state) => ({ count: state.count + 1 })),
    setName: (name) => set({ name }),
  }))
)

// Reset to initial state
useStore.reset()

IndexedDB Persistence

import { StateStorage } from 'zustand/middleware'
import { get, set, del } from 'idb-keyval'

const indexedDBStorage: StateStorage = {
  getItem: async (name: string): Promise<string | null> => {
    return (await get(name)) || null
  },
  setItem: async (name: string, value: string): Promise<void> => {
    await set(name, value)
  },
  removeItem: async (name: string): Promise<void> => {
    await del(name)
  },
}

const useStore = create<Store>()(
  persist(
    (set) => ({
      largeData: [],
      addData: (data) =>
        set((state) => ({ largeData: [...state.largeData, data] })),
    }),
    {
      name: 'large-data-storage',
      storage: createJSONStorage(() => indexedDBStorage),
    }
  )
)

Async Storage for React Native

import AsyncStorage from '@react-native-async-storage/async-storage'
import { StateStorage } from 'zustand/middleware'

const asyncStorage: StateStorage = {
  getItem: async (name: string): Promise<string | null> => {
    return await AsyncStorage.getItem(name)
  },
  setItem: async (name: string, value: string): Promise<void> => {
    await AsyncStorage.setItem(name, value)
  },
  removeItem: async (name: string): Promise<void> => {
    await AsyncStorage.removeItem(name)
  },
}

const useStore = create<Store>()(
  persist(
    (set) => ({ /* ... */ }),
    {
      name: 'app-storage',
      storage: createJSONStorage(() => asyncStorage),
    }
  )
)

Common Patterns

Conditional Persistence

Only persist certain fields:

const useStore = create<Store>()(
  persist(
    (set) => ({
      // Persisted
      theme: 'light',
      language: 'en',

      // Not persisted
      isLoading: false,
      error: null,

      setTheme: (theme) => set({ theme }),
      setLanguage: (language) => set({ language }),
    }),
    {
      name: 'settings',
      partialize: (state) => ({
        theme: state.theme,
        language: state.language,
      }),
    }
  )
)

Version Migration

Handle breaking changes in persisted state:

const useStore = create<Store>()(
  persist(
    (set) => ({ /* ... */ }),
    {
      name: 'app-store',
      version: 2,
      migrate: (persistedState: any, version: number) => {
        if (version === 0) {
          // Migrate from version 0 to 1
          persistedState.newField = 'default'
        }

        if (version === 1) {
          // Migrate from version 1 to 2
          persistedState.items = persistedState.oldItems.map((item: any) => ({
            id: item.id,
            name: item.title, // renamed field
          }))
          delete persistedState.oldItems
        }

        return persistedState as Store
      },
    }
  )
)

Hydration Detection

Know when persisted state is loaded:

const useStore = create<Store>()(
  persist(
    (set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
    }),
    {
      name: 'counter',
      onRehydrateStorage: () => (state) => {
        console.log('State hydrated:', state)
      },
    }
  )
)

// In a component
function App() {
  const [hydrated, setHydrated] = useState(false)

  useEffect(() => {
    useStore.persist.onFinishHydration(() => {
      setHydrated(true)
    })
  }, [])

  if (!hydrated) {
    return <div>Loading...</div>
  }

  return <div>App content</div>
}

Anti-Patterns

❌ Don't Persist Sensitive Data

// Bad: Persisting tokens in localStorage
const useAuthStore = create(
  persist(
    (set) => ({
      token: null,
      user: null,
      login: async (credentials) => {
        const { token, user } = await api.login(credentials)
        set({ token, user }) // ❌ Token in localStorage
      },
    }),
    { name: 'auth' }
  )
)

// Good: Use secure storage or don't persist tokens
const useAuthStore = create(
  persist(
    (set) => ({
      user: null,
      login: async (credentials) => {
        const { token, user } = await api.login(credentials)
        secureStorage.setToken(token) // ✅ Secure storage
        set({ user })
      },
    }),
    {
      name: 'auth',
      partialize: (state) => ({ user: state.user }), // ✅ Only persist user
    }
  )
)

❌ Don't Ignore Middleware Order

// Bad: DevTools won't see persisted initial state
create(persist(devtools(...)))

// Good: DevTools can see full state lifecycle
create(devtools(persist(...)))

❌ Don't Mutate State Without Immer

// Bad: Mutating without immer
const useStore = create((set) => ({
  items: [],
  addItem: (item) =>
    set((state) => {
      state.items.push(item) // ❌ Direct mutation
      return state
    }),
}))

// Good: Use immer middleware
const useStore = create(
  immer((set) => ({
    items: [],
    addItem: (item) =>
      set((state) => {
        state.items.push(item) // ✅ Safe with immer
      }),
  }))
)

❌ Don't Forget to Clean Up Subscriptions

// Bad: Memory leak
useEffect(() => {
  useStore.subscribe((state) => {
    console.log(state)
  })
}, [])

// Good: Clean up subscription
useEffect(() => {
  const unsubscribe = useStore.subscribe((state) => {
    console.log(state)
  })
  return unsubscribe
}, [])

Related Skills

  • zustand-store-patterns: Basic store creation and usage
  • zustand-typescript: TypeScript integration with middleware
  • zustand-advanced-patterns: Custom middleware and advanced techniques

平台分布

Codex

28.19%
按下载量换算77

Claude Code

23.36%
按下载量换算64

Antigravity

15.63%
按下载量换算43

OpenCode

11.8%
按下载量换算32

windsurf

7.23%
按下载量换算20

trae

3.37%
按下载量换算9

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

继续浏览同类 Skills