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
も不要です。
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)
のハンドラー (プロセッサ オブジェクト) 内のいくつかのトラップ (キャプチャラー) を指します。つまり、get
、set
これらのメソッドです。
ファクトリ関数を通じてこれらのトラップ関数を作成し、コードを簡素化し、保守性を向上させることができます。
さらに、トラップはファクトリによって生成できる、つまりハンドラー部分が決定されることに等しいと仮定します。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); }
以上がvue3でreadonlyをレスポンシブに実装する方法は何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。