reactive 嵌套
单元测试
// reactive.spec.ts
describe("reactive", () => {
it("nested reactive", () => {
const original = {
nested: {
foo: 1,
},
array: [{ bar: 2 }],
};
const observed = reactive(original);
expect(isReactive(observed.nested)).toBe(true);
expect(isReactive(observed.array)).toBe(true);
expect(isReactive(observed.array[0])).toBe(true);
});
});
想要实现嵌套 只需在 get 的时候 对类型为 object 的 res 再用 reactive 声明一下
代码实现
// shared/index.ts
export const isObject = (val) => {
return val !== null && typeof val === "object";
}
// baseHandlers.ts
function createGetter(isReadonly = false) {
return function get(target, key) {
const res = Reflect.get(target, key);
if (isObject(res)) {
return reactive(res)
}
...
}
}
readonly 嵌套
单元测试
// readonly.spec.ts
describe("readonly", () => {
it("happy path", () => {
const original = { foo: 1, bar: { baz: 2 } };
const wrapped = readonly(original);
expect(isReadonly(wrapped.bar)).toBe(true);
expect(isReadonly(original.bar)).toBe(false);
});
})
实现思路与 reactive 嵌套类似
代码实现
// baseHandler.ts
function createGetter(isReadonly = false) {
return function get(target, key) {
const res = Reflect.get(target, key);
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
}
}
shallowReadonly
单元测试
// shallowReadonly.spec.ts
describe("shallowReadonly", () => {
it("should not make non-reactive properties reactive", () => {
const props = shallowReadonly({ n: { foo: 1 } });
expect(isReadonly(props)).toBe(true);
expect(isReadonly(props.n)).toBe(false);
});
it("warn then call set", () => {
console.warn = jest.fn();
const user = shallowReadonly({ age: 10 });
user.age = 11;
expect(console.warn).toBeCalled();
});
});
shallowReadonly 的功能是使其内部的对象是个普通的对象,只有最外层的是 proxy
实现思路:在 get 的时候不用 readonly 重新包装 res,即声明一个变量判断是否是shallow,是的话直接 return res
代码实现
// baseHandlers.ts
const shallowReadonlyGet = createGetter(true, true)
function createGetter(isReadonly = false, isShallow = false) {
return function get(target, key) {
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly;
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly;
}
const res = Reflect.get(target, key);
// 如果是 shallow 直接 return
if (isShallow) {
return res;
}
// 看看 res 是不是 object
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
// 依赖收集
if (!isReadonly) {
track(target, key);
}
return res;
};
}
export const shallowReadonlyHandlers = extend({}, readonlyHandlers, {
get: shallowReadonlyGet,
});
// reactive.ts
export function shallowReadonly(raw: any) {
return createActiveObject(raw, shallowReadonlyHandlers);
}