Skip to content

Commit 8c93cbd

Browse files
committed
fix: 修复双向同步schema数据时状态数据被复位的问题
1 parent 4c4804c commit 8c93cbd

File tree

4 files changed

+113
-2
lines changed

4 files changed

+113
-2
lines changed

packages/core/src/schema/manager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class SchemaManager<
6262

6363
this._descriptors[key] = finalDescriptor;
6464

65-
if (this.shadow && descriptor.value !== undefined) {
65+
if (this.shadow && descriptor.value !== undefined && descriptor.flags !== -1) {
6666
this.shadow.update(
6767
(state) => {
6868
setVal(state, pathKey, descriptor.value);

packages/core/src/schema/types/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,11 @@ export type SchemaDescriptor<Value = any, Options = Dict> = {
258258
datatype: "string" | "number" | "boolean" | "object" | "array" | "any" | string;
259259
value: Value;
260260
options: SchemaOptions<Value, Options>;
261+
/**
262+
* 用于传递额外的标识
263+
* 比如在进行syncer时,传入falgs==SYNC_INIT_FLAG
264+
*/
265+
flags?: number;
261266
};
262267

263268
export interface SchemaDescriptorBuilder<Value = any, State = Dict> {

packages/syncer/src/__tests__/store.sync.test.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { describe, expect, test } from "vitest";
55
import { computed, AutoStore, configurable, ValidateError } from "../../../core/src";
66
import "..";
77
import { isFunction } from "../../../core/src/utils/isFunction";
8+
import { AutoStoreSyncer } from "..";
89

910
describe("本地Store同步", () => {
1011
test("一对一全同步", async () => {
@@ -1046,4 +1047,109 @@ describe("本地Store同步", () => {
10461047
});
10471048
});
10481049
});
1050+
test("模块配置同步模拟测试", async () => {
1051+
class SettingManager {
1052+
_dirtyValues: Record<string, any> = {};
1053+
store = new AutoStore(
1054+
{},
1055+
{
1056+
id: "settings",
1057+
resetable: true,
1058+
},
1059+
);
1060+
1061+
constructor(values: Record<string, any>) {
1062+
this.load(values);
1063+
// 侦听配置变化,并且在变化时进行保存
1064+
this.store.watch(({ path, value, flags }) => {
1065+
// 当从模块第一次同步更新到store时,flags<0
1066+
if (flags && flags < 0) return;
1067+
// 为什么是2? 因为path[0]是模块id,path[1]是配置项路径
1068+
if (path.length === 2) {
1069+
if (!this._dirtyValues[path[0]]) this._dirtyValues[path[0]] = {};
1070+
this._dirtyValues[path[0]][path[1]] = value;
1071+
1072+
this.save();
1073+
}
1074+
});
1075+
}
1076+
load(values: Record<string, any> = {}) {
1077+
this.store = new AutoStore(values, {
1078+
id: "settings",
1079+
resetable: true,
1080+
});
1081+
}
1082+
save() {}
1083+
}
1084+
const settingManager = new SettingManager({
1085+
shop: {
1086+
"order.price": 1000,
1087+
},
1088+
});
1089+
class ShopModule {
1090+
store = new AutoStore({
1091+
order: {
1092+
price: configurable(100),
1093+
},
1094+
});
1095+
syncer?: AutoStoreSyncer;
1096+
constructor() {
1097+
this.loadSettings();
1098+
this.sync();
1099+
}
1100+
sync() {
1101+
// 如果模块不是observable的,则不需要进行同步,同步是基于AutoStore的sync功能的
1102+
if (this.store.schemas.size === 0) {
1103+
return;
1104+
}
1105+
1106+
// 只有使用schema或configurable声明的配置项才会进行同步
1107+
const filter = (path: string[]) => {
1108+
return this.store.schemas.has(path.join(".") as any);
1109+
};
1110+
const moduleStore = this.store;
1111+
const syncSettings = {
1112+
filter,
1113+
remote: "shop",
1114+
immediate: true,
1115+
pathMap: {
1116+
toLocal: (path: any[], value: any) => {
1117+
if (typeof value !== "object") {
1118+
return path.reduce<string[]>((result: any[], cur: string) => {
1119+
result.push(...cur.split("."));
1120+
return result;
1121+
}, []);
1122+
}
1123+
},
1124+
toRemote(path: any[], value: any) {
1125+
// this.store.schemas.has(path)的作用
1126+
// 当同步configurable时,如果是数组或对象,也需要同步
1127+
if (typeof value !== "object" || moduleStore.schemas.has(path)) {
1128+
return [path.join(".")];
1129+
}
1130+
},
1131+
},
1132+
};
1133+
// 将本模块的配置项同步到全局SettingManager中,这样在应用中就可以使用SettingManager管理应用的所有配置了
1134+
this.syncer = this.store.sync(settingManager.store, syncSettings);
1135+
}
1136+
loadSettings() {
1137+
// @ts-expect-error
1138+
this.store.state.order.price = settingManager.store.state["shop"]["order.price"];
1139+
}
1140+
}
1141+
1142+
const order = new ShopModule();
1143+
expect(order.store.state.order.price).toBe(1000);
1144+
// @ts-expect-error
1145+
expect(settingManager.store.state["shop"]["order.price"]).toBe(1000);
1146+
order.store.state.order.price = 2000;
1147+
expect(order.store.state.order.price).toBe(2000);
1148+
// @ts-expect-error
1149+
expect(settingManager.store.state["shop"]["order.price"]).toBe(2000);
1150+
1151+
// @ts-expect-error
1152+
settingManager.store.state["shop"]["order.price"] = 3000;
1153+
expect(order.store.state.order.price).toBe(3000);
1154+
});
10491155
});

packages/syncer/src/syncer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
markRaw,
1414
} from "autostore";
1515
import type { AutoStoreSyncerOptions, StateRemoteOperate } from "./types";
16-
import { parseFunc } from "../../core/src/utils/parseFunc";
1716
import { markFunc } from "./utils/markFunc";
1817

1918
type NormalizeAutoStoreSyncerOptions = Required<
@@ -457,6 +456,7 @@ export class AutoStoreSyncer {
457456
datatype: schema.datatype,
458457
value: schema.value,
459458
options: schema,
459+
flags: operate.flags,
460460
});
461461
});
462462
this.store.schemas.build();

0 commit comments

Comments
 (0)