# @dhmk/zustand-lens 中文文档

规范地址：https://npmcn.com/package/%40dhmk/zustand-lens/

版本：5\.0\.0
npm 元数据更新时间：2024-10-23T17:33:29.090Z
中文译文更新时间：2026-11-12T06:17:28.294Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40dhmk/zustand-lens
原文对照：https://npmcn.com/package/%40dhmk/zustand-lens/?lang=original
源码仓库：https://github.com/dhmk083/dhmk-zustand-lens

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：101 kB，21 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：zustand ^5\.0\.0
- 首次发布：2021-12-27T20:05:00.557Z
- 最新版本发布：2024-10-23T17:33:28.866Z
- 近 30 天下载量：130624（2026-10-12 至 2026-11-10，npm 官方下载统计）
- 已发布版本数：27（近 12 个月 0 个）

## 中文简介

月球支持 zustand

## 安装

```sh
npm install @dhmk/zustand-lens
```

也可以使用：`pnpm add @dhmk/zustand-lens`、`yarn add @dhmk/zustand-lens`、`bun add @dhmk/zustand-lens`

## README

# @dhmk/zustand-lens (英语)

镜头支持 [zu子](https://github.com/pmndrs/zustand)。 。 。 .

通过这个软件包,您可以轻松地管理您主状态内的嵌入状态. 镜头允许您创建孤立和可再使用的组件.

一个镜头有一对功能 `set` 财务报告和审定财务报表 `get` 它们具有与zustand的功能相同的签名,但它们只在某个特定的主状态上运行.

简单比较一下:

```ts
import create from "zustand";
import { withLenses, lens } from "@dhmk/zustand-lens";

create(
  withLenses((set, get) => {
    // write and read whole state

    return {
      subStore: lens((subSet, subGet) => {
        // write and read `subStore` state
      }),
    };
  })
);
```

## 安装

```sh
npm install @dhmk/zustand-lens
```

## 使用量

```ts
import { create } from 'zustand'
import { withLenses, lens } from '@dhmk/zustand-lens'

// set, get - global
const useStore = create(withLenses((set, get, api) => {
  return {
    // set, get - only for storeA
    storeA: lens((set, get, api) => ({
      data: ...,

      action: (arg) => set({data: arg})
    })),

    // set, get - only for storeB
    storeB: lens((set, get, api) => ({
      data: ...,

      action: (arg) => set({data: arg})
    })),

    globalStore: {
      data: ...,

      action: () => set({...}) // global setter
    }
  }
}))

// or use a shorter version if you don't need global `set` and `get`
create(withLenses({
  storeA: lens(...),
  storeB: lens(...)
}))
```

## API 密码

### `withLenses(config: (set, get, api) => T): T`

### `withLenses(obj: T): T`

中间软件功能.

它召唤 `config` 函数与默认 zustand 的参数相同 `create` 函数,然后转换返回的对象,以扩展全部 `lens` 实例到合适的对象.

也可以提供普通对象而不是函数.

### `lens(fn: (set, get, api, context) => T): T`

创建透镜对象.

前两个参数 `set` 财务报告和审定财务报表 `get` 用于编写和读取全局状态子集的函数,相对于一个位置 `lens` 显示。 第三个, `api` 参数为zustand store 和最后一个参数 `context` 是一个镜头上下文.

```ts
type LensContext<T, S> = {
  set: Setter<T>; // `set` parameter
  get: Getter<T>; // `get` parameter
  api: ResolveStoreApi<S>; // `api` parameter
  rootPath: ReadonlyArray<string>; // path from root level of state
  relativePath: ReadonlyArray<string>; // path from parent lens or root
  atomic: (fn: () => void) => void; // see `atomic` middleware
};
```

斯特尔有这个签名: `(value: Partial<T> | ((prev: T) => Partial<T>), replace?: boolean, ...args) => void`。它将未知的参数传递给顶层 `set` 函数.

**警告**: 您不应该在代码中使用此函数的返回值。 它返回不透明对象,该对象通过 `withLenses` 函数.

**页:1**: 此函数用于在外部调用时抛出错误 `withLenses` 函数。 这是用来重音 `lens` 无法在之后动态创建 `withLenses` 已被调用。 但事先创建镜头是好的,所以我消除了这个错误(1.0.3和2.0.3). 现在你可以这样叫它:

```js
const todosSlice = lens(() => ...)
const usersSlice = lens(() => ...)

const useStore = create(withLenses({
  todosSlice,
  usersSlice,
}))
```

另外,如果您想要将您的功能与 `lens` 包装 :

```ts
import { Lens, lens } from "@dhmk/zustand-lens";

/*
type Lens<
  T,      // slice type
  S,      // store state type or store api type
  Setter  // `set` function type
>
*/

type MenuState = {
  isOpened: boolean;

  toggle(open);
};

// `set` and `get` are typed
const menuState: Lens<MenuState> = (set, get, api) => ({
  isOpened: false,

  toggle(open) {
    set({ isOpened: open });
  },
});

const menuSlice = lens(menuState);
```

### `createLens(set, get, path: string | string[]): [set, get]`

创建清晰的镜头对象.

这需要 `set` 财务报告和审定财务报表 `get` 参数和 `path` 返回一对设置器和获取器,该设置器和获取器运行在父状态的子集上,相对于 `path`你可以连锁镜头。 另外,您也可以将此函数作为独立函数使用,而不包含 `withLenses` 中间软件.

```ts
import { create } from "zustand";
import { createLens } from "@dhmk/zustand-lens";

const useStore = create((set, get) => {
  const lensA = createLens(set, get, "a");
  const lensB = createLens(...lensA, "b");
  const [setC] = createLens(...lensB, "c");

  return {
    a: {
      b: {
        c: {
          value: 111,
        },
      },
    },

    changeValue: (value) => setC({ value }),
  };
});

useStore.getState().changeValue(222);

console.log(useStore.getState());
/*
a: {
  b: {
    c: {
      value: 222
    }
  }
}
*/
```

## 字体

```ts
type Store = {
  id: number;
  name: string;

  nested: Nested;
};

type Nested = {
  text: string;
  isOk: boolean;

  toggle();
};

// option 1: type whole store
const store1 = create<Store>(
  withLenses({
    id: 123,
    name: "test",

    nested: lens((set) => ({
      text: "test",
      isOk: true,

      toggle() {
        set((p /* Nested */) => ({ isOk: !p.isOk }));
      },
    })),
  })
);

// option 2: type lens
const store2 = create(
  withLenses({
    id: 123,
    name: "test",

    nested: lens<Nested>((set) => ({
      text: "test",
      isOk: true,

      toggle() {
        set((p /* Nested */) => ({ isOk: !p.isOk }));
      },
    })),
  })
);
```

## 缩合

Immer被支持出柜. 然而,有一个告诫。 草稿的类型是 `T` 没有 `Draft<T>`。您可以自己添加,也可以不使用只读属性.

```ts
import { immer } from "zustand/middleware/immer";

const store = create<Store>()(
  immer(
    withLenses({
      id: 123,
      name: "test",

      nested: lens((set) => ({
        text: "test",
        isOk: true,

        toggle() {
          set((p /* Nested */) => {
            p.isOk = !p.isOk;
          });
        },
      })),
    })
  )
);
```

## 镜头中间软件

自兹 `lens` 取一个普通的功能,你可以用各种中件进行镜头对象的预处理,用zustand的同样方式进行.

此示例使用自定义 `set` 函数,它需要一个新的状态和记录的动作名称.

查看关于如何写作和打入中间软件的提示的源代码 .

```ts
import { lens, namedSetter } from "@dhmk/zustand-lens";

const test = lens(
  namedSetter((set) => ({
    name: "abc",

    setName() {
      set({ name: "def" }, "@test/setName");
    },
  }))
);
```

甚至可以创建自定义镜头.

```ts
import { lens, namedSetter } from "@dhmk/zustand-lens";

const lensWithNamedSetter = <T, S = unknown>(
  fn: Lens<T, S, NamedSet<T>>
): LensOpaqueType<T, S> => lens(namedSetter(fn));
```

## 高级选项

### `atomic(stateCreator)`

原子集操作的中间软件. 原子操作可以有多个调用: `setState` 函数,但附加的回调 `subscribe` 函数只在原子块结尾处调用一次。 此中间软件启用 `atomic` 从镜头上下文的函数,并制作 `[meta].setter` 函数原子.

### `[meta]`

高级镜头配置. 您可以将这个符号放入镜头或根态中. 如果您正在使用 Typescript 并想要将此符号添加到根状态, 您可能会遇到错误 。 在这种情况下,使用下列方法:

```ts
// add { [meta] } to your state type
create<State & { [meta] }>()(
  withLenses({
    // ...

    [meta]: {
      // ...
    },
  })
);
```

这个 `[meta]` 对象接受下列可选属性:

#### `postprocess(state: T, prevState: T, ...args): Partial<T> | void`

此函数在调用后调用 `set` 函数在将新状态合并到父状态之前 `set` 函数。 它被称作一个新的临时状态, 将被汇入,当前状态 和所有额外的论据, 被传递到一个 `set` 函数。 你可以回到新州,它会我与一个 `state` 参数。 此函数必须纯洁 。 你可以变异 `state` 参数仅在使用时 `immer` 中间软件.

#### `setter(next: Function, context: LensContext): void`

当调用镜头( 或 root) 时, 此函数会被调用 `set` 函数。 这样可以自定义预设和后设定的行为. 你可以在这里运行副作用。 你应该打电话 `next` 函数一次并同步将设置的操作委托给一个母镜(或root),类似于 `next` 函数在 `express.js`。如果您正在使用 [`atomic`](https://npmcn.com/package/%40dhmk/zustand-lens/#readme-atomic) 中间软件,此函数将在原子上执行 。 也请使用 [`watch`](https://npmcn.com/package/%40dhmk/zustand-lens/#readme-watch) 帮助方便运行状态变化的副作用.

### `Understanding order of invocation.`

鉴于以下商店:

```ts
const store = create(
  withLenses({
    someSlice: lens(() => ({
      nested: lens((set) => ({
        id: 1,
        test() {
          console.log("test before");
          set({ id: 2 });
          console.log("test after");
        },
        [meta]: {
          postprocess() {
            console.log("nested postprocess");
          },
          setter(set) {
            console.log("nested setter before");
            set();
            console.log("nested setter after");
          },
        },
      })),
      [meta]: {
        postprocess() {
          console.log("someSlice postprocess");
        },
        setter(set) {
          console.log("someSlice setter before");
          set();
          console.log("someSlice setter after");
        },
      },
    })),
    [meta]: {
      postprocess() {
        console.log("root postprocess");
      },
      setter(set) {
        console.log("root setter before");
        set();
        console.log("root setter after");
      },
    },
  })
);

store.getState().someSlice.nested.test();
```

控制台日志如下:

```
test before

nested setter before
someSlice setter before
root setter before

nested postprocess
someSlice postprocess
root postprocess

root setter after
someSlice setter after
nested setter after

test after
```

## 杂项

### `mergeDeep(a, b)`

### `mergeDeep(b)(a)`

合并对象 `b` 与 `a` 递归( 不合并数组) .

### `mergeDeepLeft(a, b)`

合并对象 `a` 与 `b` (注释顺序). 有用吗 `persist` 中间软件.

### `persistOptions`

帮助工具 `persist` 中间软件。 可以用不带镜头。 首先,你需要添加这些选项来坚持自己的配置. 现在您可以在您状态下的任何对象上附加选项,只需拨打 `persistOptions` 作为函数,并为对象提供两种可选函数: `save` 财务报告和审定财务报表 `load`每当你需要坚持状态, `save` 函数将被调用并持续返回值。 同样, `load` 函数将调用水合。 这使得您可以控制您想要保存/恢复哪些数据 。 两种功能必须纯洁,不要变换提供的论点.

```ts
const store = create(persist(() => ({
  // ... some state

  ...persistOptions({
    save(state) {
      // return an object that will be saved
    },

    load(persistedState) {
      // return an object that will be used as new state
    }
  })

  nested: {
    // ... some state

    // can be nested too
    ...persistOptions({
      save
      load
    })
  }
}), {
  name: 'my-store',
  // don't forget to add options to persist config
  ...persistOptions
}))
```

### `subscribe(store, selector, effect, options?)`

备选案文 [`subscribeWithSelector`](https://github.com/pmndrs/zustand#using-subscribe-with-selector) 中间软件.

### `watch(selector, effect, options?)`

类似 `subscribe` 函数,用于 `setter` 钩. 这叫镜头 `set` 函数先运行 `effect` 函数。 不需要退订.

### `combineWatchers(...watchers)`

依次运行监视器(或任何类似设置的功能). 如果你有多个监视器,那就有用了。 示例

```ts
[meta]: {
  setter: combineWatchers(
    watch(state => state.id, handleIdChange),
    watch(state => state.name, handleNameChange)
  )
}
```

## 常见问题

### @dhmk/zustand-lens 是什么？

月球支持 zustand

### 如何安装 @dhmk/zustand-lens？

在项目目录运行 npm install @dhmk/zustand-lens，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：zustand（^5\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @dhmk/zustand-lens 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @dhmk/zustand-lens 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @dhmk/zustand-lens 可以商用吗？

@dhmk/zustand-lens 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @dhmk/zustand-lens 的下载量有多少？

根据 npm 官方下载统计，@dhmk/zustand-lens 在 2026/10/12 – 2026/11/10 这 30 天内被下载 130,624 次，日均约 4,354 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @dhmk/zustand-lens 还在维护吗？

最新版本 5\.0\.0 发布于 2024/10/24（2 年前）；至今共发布 27 个版本，其中过去 12 个月发布了 0 个；首次发布于 2021/12/28。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

