@dhmk/zustand-lens (英语)
镜头支持 zu子。 。 。 .
通过这个软件包,您可以轻松地管理您主状态内的嵌入状态. 镜头允许您创建孤立和可再使用的组件.
一个镜头有一对功能 set 财务报告和审定财务报表 get 它们具有与zustand的功能相同的签名,但它们只在某个特定的主状态上运行.
简单比较一下:
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
}),
};
})
);
安装
npm install @dhmk/zustand-lens
使用量
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 是一个镜头上下文.
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). 现在你可以这样叫它:
const todosSlice = lens(() => ...)
const usersSlice = lens(() => ...)
const useStore = create(withLenses({
todosSlice,
usersSlice,
}))
另外,如果您想要将您的功能与 lens 包装 :
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 中间软件.
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
}
}
}
*/
字体
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>。您可以自己添加,也可以不使用只读属性.
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 函数,它需要一个新的状态和记录的动作名称.
查看关于如何写作和打入中间软件的提示的源代码 .
import { lens, namedSetter } from "@dhmk/zustand-lens";
const test = lens(
namedSetter((set) => ({
name: "abc",
setName() {
set({ name: "def" }, "@test/setName");
},
}))
);
甚至可以创建自定义镜头.
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 并想要将此符号添加到根状态, 您可能会遇到错误 。 在这种情况下,使用下列方法:
// 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 中间软件,此函数将在原子上执行 。 也请使用 watch 帮助方便运行状态变化的副作用.
Understanding order of invocation.
鉴于以下商店:
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 函数将调用水合。 这使得您可以控制您想要保存/恢复哪些数据 。 两种功能必须纯洁,不要变换提供的论点.
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 中间软件.
watch(selector, effect, options?)
类似 subscribe 函数,用于 setter 钩. 这叫镜头 set 函数先运行 effect 函数。 不需要退订.
combineWatchers(...watchers)
依次运行监视器(或任何类似设置的功能). 如果你有多个监视器,那就有用了。 示例
[meta]: {
setter: combineWatchers(
watch(state => state.id, handleIdChange),
watch(state => state.name, handleNameChange)
)
}