• 简体中文
  • devtools

    devtools 中间件让你无需 Redux 也能使用 Redux DevTools Extension。要进一步了解使用 Redux DevTools 进行调试的好处,请点击链接阅读。

    WARNING

    要在 zustand/middleware 中使用 devtools,你需要安装 @redux-devtools/extension 库。

    const nextStateCreatorFn = devtools(stateCreatorFn, devtoolsOptions)

    类型

    签名

    devtools<T>(stateCreatorFn: StateCreator<T, [], []>, devtoolsOptions?: DevtoolsOptions): StateCreator<T, [['zustand/devtools', never]], []>

    Mutator

    ;['zustand/devtools', never]

    参考

    devtools(stateCreatorFn, devtoolsOptions)

    参数

    • stateCreatorFn:一个接收 set 函数、get 函数和 store 作为参数的函数。 通常,你会返回一个对象,其中包含你想对外暴露的方法。
    • 可选 devtoolsOptions:一个用于定义 Redux Devtools 选项的对象。
      • 可选 name:Redux DevTools 中该连接的自定义标识符。
      • 可选 enabled:在开发模式下默认为 true,在生产模式下默认为 false。 用于启用或禁用该 store 的 Redux DevTools 集成。
      • 可选 anonymousActionType:默认为推断出的 action 类型;若无法推断,则为 anonymous。 一个字符串,在 Redux DevTools 中用作匿名变更的 action 类型。
      • 可选 store:Redux DevTools 中该 store 的自定义标识符。
      • 可选 actionsDenylist:一个字符串或字符串数组(正则表达式模式),用于指定哪些 action 应从 Redux DevTools 中过滤掉。该选项会直接传给 Redux DevTools 用于过滤。 例如,['secret.*'] 会过滤掉所有以 "secret" 开头的 action。

    返回值

    devtools 返回一个 state creator 函数。

    用法

    调试 store

    以下示例展示了如何使用 Redux Devtools 调试一个 store

    import { create, StateCreator } from 'zustand'
    import { devtools } from 'zustand/middleware'
    
    type JungleStore = {
      bears: number
      addBear: () => void
      fishes: number
      addFish: () => void
    }
    
    const useJungleStore = create<JungleStore>()(
      devtools((set) => ({
        bears: 0,
        addBear: () => set((state) => ({ bears: state.bears + 1 }), undefined, 'jungle/addBear'),
        fishes: 0,
        addFish: () => set((state) => ({ fishes: state.fishes + 1 }), undefined, 'jungle/addFish'),
      })),
    )

    调试基于切片模式的 store

    以下示例展示了如何使用 Redux Devtools 调试基于切片模式的 store

    import { create, StateCreator } from 'zustand'
    import { devtools } from 'zustand/middleware'
    
    type BearSlice = {
      bears: number
      addBear: () => void
    }
    
    type FishSlice = {
      fishes: number
      addFish: () => void
    }
    
    type JungleStore = BearSlice & FishSlice
    
    const createBearSlice: StateCreator<JungleStore, [['zustand/devtools', never]], [], BearSlice> = (
      set,
    ) => ({
      bears: 0,
      addBear: () => set((state) => ({ bears: state.bears + 1 }), undefined, 'jungle:bear/addBear'),
    })
    
    const createFishSlice: StateCreator<JungleStore, [['zustand/devtools', never]], [], FishSlice> = (
      set,
    ) => ({
      fishes: 0,
      addFish: () => set((state) => ({ fishes: state.fishes + 1 }), undefined, 'jungle:fish/addFish'),
    })
    
    const useJungleStore = create<JungleStore>()(
      devtools((...args) => ({
        ...createBearSlice(...args),
        ...createFishSlice(...args),
      })),
    )

    使用 actionsDenylist 过滤 action

    你可以使用 actionsDenylist 选项从 Redux DevTools 中过滤掉特定的 action。当你想在 DevTools 时间线中隐藏内部或敏感的 action 时,这个选项非常有用。

    import { create } from 'zustand'
    import { devtools } from 'zustand/middleware'
    
    type Store = {
      user: string | null
      token: string | null
      login: (user: string, token: string) => void
      logout: () => void
      updateData: () => void
    }
    
    const useStore = create<Store>()(
      devtools(
        (set) => ({
          user: null,
          token: null,
          login: (user, token) => set({ user, token }, undefined, 'auth/login'),
          logout: () => set({ user: null, token: null }, undefined, 'auth/logout'),
          updateData: () => set({ user: 'updated' }, undefined, 'internal/updateData'),
        }),
        {
          name: 'AuthStore',
          // Filter out actions matching these regex patterns
          actionsDenylist: ['internal/.*'], // Hides all 'internal/*' actions
        },
      ),
    )

    你也可以只传一个正则表达式字符串:

    const useStore = create<Store>()(
      devtools(
        (set) => ({
          // ... state and actions
        }),
        {
          name: 'MyStore',
          actionsDenylist: 'secret.*', // Hides all actions starting with 'secret'
        },
      ),
    )
    NOTE

    actionsDenylist 选项使用正则表达式模式匹配,并由 Redux DevTools Extension 直接处理。 所有 action 仍会发送到 DevTools,但匹配的 action 会从显示中过滤掉。

    清理

    当不再需要某个 store 时,你可以通过调用该 store 上的 cleanup 方法来清理 Redux DevTools 连接:

    import { create } from 'zustand'
    import { devtools } from 'zustand/middleware'
    
    const useStore = create(
      devtools((set) => ({
        count: 0,
        increment: () => set((state) => ({ count: state.count + 1 })),
      })),
    )
    
    // When you're done with the store, clean it up
    useStore.devtools.cleanup()

    在把 store 包装进上下文、或动态创建多个 store 的应用中,这一点尤其有用。

    疑难解答

    只显示一个 store

    默认情况下,Redux Devtools 一次只显示一个 store,因此要查看其他 store,你需要使用 store 选择器并选择另一个 store。

    所有 action 名称都被标记为 'anonymous'

    如果没有提供 action 类型名,它就会默认为 "anonymous"。你可以通过提供 anonymousActionType 参数来自定义这个默认值:

    例如,下面的示例就没有指定 action 类型名:

    import { create, StateCreator } from 'zustand'
    import { devtools } from 'zustand/middleware'
    
    type BearSlice = {
      bears: number
      addBear: () => void
    }
    
    type FishSlice = {
      fishes: number
      addFish: () => void
    }
    
    type JungleStore = BearSlice & FishSlice
    
    const createBearSlice: StateCreator<JungleStore, [['zustand/devtools', never]], [], BearSlice> = (
      set,
    ) => ({
      bears: 0,
      addBear: () => set((state) => ({ bears: state.bears + 1 })),
      eatFish: () => set((state) => ({ fishes: state.fishes - 1 })),
    })
    
    const createFishSlice: StateCreator<JungleStore, [['zustand/devtools', never]], [], FishSlice> = (
      set,
    ) => ({
      fishes: 0,
      addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
    })
    
    const useJungleStore = create<JungleStore>()(
      devtools((...args) => ({
        ...createBearSlice(...args),
        ...createFishSlice(...args),
      })),
    )

    要修复上面的示例,我们需要把 action 类型名作为第三个参数传入。此外,为了保留替换逻辑的默认行为,第二个参数应设为 undefined。

    下面是修复后的示例

    import { create, StateCreator } from 'zustand'
    import { devtools } from 'zustand/middleware'
    
    type BearSlice = {
      bears: number
      addBear: () => void
    }
    
    type FishSlice = {
      fishes: number
      addFish: () => void
    }
    
    type JungleStore = BearSlice & FishSlice
    
    const createBearSlice: StateCreator<JungleStore, [['zustand/devtools', never]], [], BearSlice> = (
      set,
    ) => ({
      bears: 0,
      addBear: () => set((state) => ({ bears: state.bears + 1 }), undefined, 'bear/addBear'),
    })
    
    const createFishSlice: StateCreator<JungleStore, [['zustand/devtools', never]], [], FishSlice> = (
      set,
    ) => ({
      fishes: 0,
      addFish: () => set((state) => ({ fishes: state.fishes + 1 }), undefined, 'fish/addFish'),
    })
    
    const useJungleStore = create<JungleStore>()(
      devtools((...args) => ({
        ...createBearSlice(...args),
        ...createFishSlice(...args),
      })),
    )
    WARNING

    除非你想覆盖默认的替换逻辑,否则不要把第二个参数设为 true 或 false