Skip to content

Commit

Permalink
feat: 组件实例增加cloneData字段
Browse files Browse the repository at this point in the history
data、store、computed可写内部字段 (_开头)

去除computed中data字段的readonlyDeep
  • Loading branch information
missannil committed Feb 1, 2024
1 parent eccf154 commit a2bc52d
Show file tree
Hide file tree
Showing 37 changed files with 407 additions and 155 deletions.
3 changes: 3 additions & 0 deletions jest/cloneData/DemoA.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"component": true
}
33 changes: 33 additions & 0 deletions jest/cloneData/DemoA.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { load, render, sleep } from "miniprogram-simulate";
import path from "path";
export const mockFn = jest.fn();

describe("cloneData", () => {
const id = load(path.resolve(__dirname, "DemoA")); // 此处必须传入绝对路径
const comp = render(id); // 渲染成自定义组件树实例

const parent = document.createElement("parent-wrapper"); // 创建挂载(父)节点

comp.attach(parent); // attach 到父亲节点上,此时会触发自定义组件的 attached 钩子

test("cloneData与data深度相等但不是一个引用值", async () => {
// 1. cloneData与data不是一个引用值
expect(comp.instance.data).not.toBe(comp.instance.cloneData);

// 2. cloneData与data深度相等
expect(comp.instance.data).toEqual(comp.instance.cloneData);

await sleep(300);

// 3. setData后,cloneData也会的值随之改变
expect(comp.instance.data.str).toBe("xxxx");

expect(comp.instance.data.obj1).toEqual({ name: "zhao", age: 20 });

// 3. cloneData与data不是一个引用值
expect(comp.instance.data).not.toBe(comp.instance.cloneData);

// 4. cloneData与data深度相等
expect(comp.instance.data).toEqual(comp.instance.cloneData);
});
});
58 changes: 58 additions & 0 deletions jest/cloneData/DemoA.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { DefineComponent, type DetailedType, RootComponent, SubComponent } from "../../src";
import type { ComponentDoc } from "../../src/api/DefineComponent/ReturnType/ComponentDoc";
import { type User, user } from "../common";

type SubA = ComponentDoc<{
properties: {
aaa_str: string;
aaa_num: number;
aaa_user: User | null;
};
}>;

const subA = SubComponent<Root, SubA>()({
inherit: {
aaa_str: "str",
},
data: {
aaa_num: 123,
},
computed: {
aaa_user() {
return user;
},
},
});

type Root = typeof rootComponent;

const rootComponent = RootComponent()({
properties: {
obj: Object as DetailedType<User>,
},
data: {
str: "string",
obj1: user,
},
computed: {
obj2() {
return user;
},
},
lifetimes: {
attached() {
setTimeout(() => {
this.setData({
str: "xxxx",
obj1: { name: "zhao", age: 20 },
});
}, 200);
},
},
});

DefineComponent({
name: "customeTest",
rootComponent,
subComponents: [subA],
});
Empty file added jest/cloneData/DemoA.wxml
Empty file.
68 changes: 34 additions & 34 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@
"prepare": "husky install",
"lint": "eslint . --fix && npm run fmt",
"fmt": "dprint fmt",
"test:jest": "jest --watch",
"test:type": "tsc --watch",
"type": "npm run test:type",
"jest": "npm run test:jest",
"type": "tsc --watch",
"jest": "jest --watch",
"build": "tsc -p tsconfig.build.json"
},
"devDependencies": {
Expand All @@ -28,6 +26,7 @@
"commitlint": "^17.6.5",
"eslint": "^8.54.0",
"eslint-plugin-tsdoc": "^0.2.17",
"hry-types": "^0.18.1",
"husky": "^8.0.3",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
Expand All @@ -54,7 +53,6 @@
"author": "missannil",
"license": "MIT",
"peerDependencies": {
"hry-types": "^0.17.0",
"miniprogram-api-typings": "^3.12.2"
}
}
15 changes: 14 additions & 1 deletion src/api/DefineComponent/assignOptions/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Func } from "hry-types/src/Misc/_api";
import { BBeforeCreate } from "../../../behaviors/BbeforeCreated";

import type { Assign } from "../../../types/Assign";
import type { WMComponent } from "../../../types/OfficialTypeAlias";
import { deepClone } from "../../../utils/deepClone";
Expand Down Expand Up @@ -34,6 +33,7 @@ import { initStore } from "./initStore";
type InstanceInnerFields = {
data: OptionsInnerFields["data"];
disposer: Record<string, Func>;
cloneData: OptionsInnerFields["data"];
} & OptionsInnerFields["methods"];

export type Instance =
Expand Down Expand Up @@ -101,6 +101,13 @@ export function isPageCheck(isPage: boolean | undefined) {
};
}

function addCloneDataToInstance(this: Instance) {
this.cloneData = new Proxy(this.data, {
get: <T extends object>(target: T, key: keyof T) => {
return deepClone(target)[key];
},
});
}
/**
* 原生Component会对传入的对象字段匹配的properties字段setData赋值。不符合字段或Page时不会赋值。
* 此函数为给实例setData赋值,默认传递值与properties相符(ts类型安全)。
Expand Down Expand Up @@ -439,6 +446,12 @@ export function assignOptions(
[isPageCheck(rootComponentOption?.isPage)],
);

hijack(
finalOptionsForComponent.lifetimes!,
"created",
[addCloneDataToInstance],
);

// 页面时删除预设的虚拟组件字段
finalOptionsForComponent.isPage
&& finalOptionsForComponent.options && Reflect.deleteProperty(finalOptionsForComponent.options, "virtualHost");
Expand Down
7 changes: 6 additions & 1 deletion src/api/RootComponent/Computed/ComputedOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import type { DuplicateFieldValidator } from "hry-types/src/Generic/DuplicateFie

import type { ComputedConstraint } from "./ComputedConstraint";

export type ComputedOption<TComputed extends ComputedConstraint, CompareKeys extends PropertyKey> = {
export type ComputedOption<
TComputed extends ComputedConstraint,
CompareKeys extends PropertyKey,
Instance extends object,
> = {
/**
* computed字段, [类型约束ComputedConstraint](ComputedConstraint.ts)
* @remarks
Expand All @@ -28,5 +32,6 @@ export type ComputedOption<TComputed extends ComputedConstraint, CompareKeys ext
*/
computed?:
& TComputed
& ThisType<Instance>
& DuplicateFieldValidator<TComputed, CompareKeys>;
};
4 changes: 3 additions & 1 deletion src/api/RootComponent/Computed/GetComputedDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ import type { ComputedConstraint } from "./ComputedConstraint";
* @param T - ComputedConstraint
* @returns object
*/
export type GetComputedDoc<TComputed extends ComputedConstraint> = { [k in keyof TComputed]: ReturnType<TComputed[k]> };
export type GetComputedDoc<TComputed extends ComputedConstraint> = {
[k in keyof TComputed]: ReturnType<TComputed[k]>;
};
4 changes: 2 additions & 2 deletions src/api/RootComponent/Computed/test/error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ RootComponent()({
},
computed: {
// @ts-expect-error '与properties字段重复'
str() {
str(): string {
return "与properties字段重复";
},
// @ts-expect-error "与data字段重复"
num() {
num(): string {
return "与data字段重复";
},
},
Expand Down
24 changes: 13 additions & 11 deletions src/api/RootComponent/Computed/test/normal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const RootDoc = RootComponent()({
},
data: {
lastName: "lastName",
mock_User: {} as Mock_User,
},
store: {
prefix: () => "hry-", // 模拟而已
Expand All @@ -30,17 +31,18 @@ const RootDoc = RootComponent()({
// 3 this.data 类型是深度只读的
Checking<
typeof this.data,
ReadonlyDeep<
{
firstName: string;
lastName: string;
fullName: string;
user: Mock_User;
prefix: string;
id_fullName: string;
readOnly: "str";
} & IInjectData
>,
{
firstName: string;
lastName: string;
mock_User: Mock_User;
fullName: string;
user: Mock_User;
prefix: string;
id_fullName: string;
readOnly: "str";
injectStr: string;
injectTheme: "light" | "dark" | undefined;
},
Test.Pass
>;

Expand Down

0 comments on commit a2bc52d

Please sign in to comment.