it("happy path", () => { console.warn = vi.fn(); const original = { foo: 1, }; const observed = readonly({ foo: 1, }); expect(original).not.toBe(observed); expect(observed.foo).toBe(1); // set不起作用 observed.foo = 2; expect(observed.foo).toBe(1); // 当被set的时候,发出一个警告 expect(console.warn).toBeCalled(); });
의 구현은 실제로 이전의 reactive
구현과 매우 유사합니다. 차이점은 set
가 사용될 때 트리거가 트리거되지 않지만 경고가 발생한다는 것입니다. . 물론 변경되지 않으므로 track
은 필요하지 않습니다. reactive
十分的类似,区别只不过是set
的时候不要触发trigger,而是警告。当然既然是不会被改变的,track
也是不必要的。
export function readonly(raw) { return new Proxy(raw, { get(target, key) { const res = Reflect.get(target, key); return res; }, set(target, key, newValue, receiver) { console.warn( `property: ${String(key)} can't be set, beacase ${target} is readonly.` ); return true; }, }); } export function reactive(raw) { return new Proxy(raw, { get(target, key) { const res = Reflect.get(target, key); // 依赖收集 track(target, key); return res; }, set(target, key, value) { const res = Reflect.set(target, key, value); // 触发依赖 trigger(target, key); return res; }, }); }
可以看到,readonly
和 reactive
实现其实很类似,那我们可以重构一下,增强后续的拓展性。
至于我说的类似,指的是 new Proxy(target, handlers)
中的handlers(处理器对象)中的一些traps(捕获器)。即get
, set
这些方法。
我们可以通过工厂函数来创建那些traps函数,来简化我们的代码,提高可维护性。
另外,我们假定traps可以有工厂可以生产了,即handlers这部分相当于被定下来了,new Proxy
这部分也理应可以通过工厂函数创造出来。
我们先抽出一个公共的文件 baseHandler.ts
// baseHanlder.ts import { track, trigger } from "./effect"; // get的工厂函数 function createGetter(isReadonly = false) { return function get(target, key) { const res = Reflect.get(target, key); if (!isReadonly) { track(target, key); } return res; }; } function createSetter() { return function set(target, key, newValue, receiver) { const res = Reflect.set(target, key, newValue, receiver); trigger(target, key, type, newValue); return res; }; } export const mutableHandler = { get: createGetter(), set: createSetter(), }; export const readonlyHandler = { get: createGetter(), set(target, key, newValue, receiver) { console.warn( `property: ${String(key)} can't be set, beacase ${target} is readonly.` ); return true; };
然后是我们的reactive.ts
// reactive.ts import { mutableHandler, readonlyHandler, } from "./baseHandlers"; // proxy的工厂函数 function createReactiveObject( target, baseHandlers: ProxyHandler<any> ) { return new Proxy(target, baseHandlers); } export function reactive(target) { return createReactiveObject(target, mutableHandler); } export function readonly(target) { return createReactiveObject(target, readonlyHandler); }
readonly
와 reactive
의 구현이 실제로 매우 유사하다는 것을 알 수 있으므로 리팩터링하여 후속 확장성을 향상할 수 있습니다. 🎜🎜내가 말한 것과 비슷하다는 것은 new Proxy(target, handlers)
의 핸들러(프로세서 개체)에 있는 일부 트랩(캡처러)을 의미합니다. 즉, 이러한 메소드를 get
, set
합니다. 🎜🎜팩토리 함수를 통해 트랩 함수를 생성하여 코드를 단순화하고 유지 관리성을 향상시킬 수 있습니다. 🎜🎜또한 트랩은 팩토리에서 생성할 수 있다고 가정합니다. 즉 핸들러 부분은 결정되는 것과 동일하며 새 프록시
부분도 팩토리 함수를 통해 생성되어야 합니다. 🎜🎜먼저 공개 파일 baseHandler.ts
🎜rrreee🎜를 추출한 다음 reactive.ts
🎜rrreee를 추출합니다.위 내용은 vue3에서 반응적으로 읽기 전용을 구현하는 방법은 무엇입니까의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!