{console.warn=vi.fn();constoriginal={foo:1,};constobserved=readonly({foo:1,});expect(original). not.toBe(observed);expect(observed.foo).toBe(1);//set不起作用observed.foo=2;expect(observed.foo).toBe(1);//當被set的時候,"/> {console.warn=vi.fn();constoriginal={foo:1,};constobserved=readonly({foo:1,});expect(original). not.toBe(observed);expect(observed.foo).toBe(1);//set不起作用observed.foo=2;expect(observed.foo).toBe(1);//當被set的時候,">

首頁  >  文章  >  web前端  >  vue3響應式實作readonly的方法是什麼

vue3響應式實作readonly的方法是什麼

WBOY
WBOY轉載
2023-05-20 22:19:221481瀏覽

readonly的實作

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 的時候不要觸發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; 
        }, 
    }); 
}

重構

可以看到,readonlyreactive 實作其實很類似,那我們可以重構一下,增強後續的拓展性。

至於我說的類似,指的是 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);
}

以上是vue3響應式實作readonly的方法是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除