vue3響應式實現(xiàn)readonly從零開始教程
前言
前面的章節(jié)我們把 effect 部分大致講完了,這部分我們來講 readonly以及重構一下reactive。
readonly的實現(xiàn)
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的時候,發(fā)出一個警告
expect(console.warn).toBeCalled();
});
其實與我們之前實現(xiàn) reactive 十分的類似,區(qū)別只不過是set 的時候不要觸發(fā)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);
// 觸發(fā)依賴
trigger(target, key);
return res;
},
});
}
重構
可以看到,readonly 和 reactive 實現(xiàn)其實很類似,那我們可以重構一下,增強后續(xù)的拓展性。
至于我說的類似,指的是 new Proxy(target, handlers) 中的handlers(處理器對象)中的一些traps(捕獲器)。即get, set 這些方法。
我們可以通過工廠函數(shù)來創(chuàng)建那些traps函數(shù),來簡化我們的代碼,提高可維護性。
另外,我們假定traps可以有工廠可以生產了,即handlers這部分相當于被定下來了,new Proxy 這部分也理應可以通過工廠函數(shù)創(chuàng)造出來。
我們先抽出一個公共的文件 baseHandler.ts
// baseHanlder.ts
import { track, trigger } from "./effect";
// get的工廠函數(shù)
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的工廠函數(shù)
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);
}
結束
本篇幅比較短小,但是算是為后續(xù)打下了一些基礎吧。因為筆者發(fā)現(xiàn)邊學邊寫總結文章速度很慢,然后寫完 effect 那幾篇之后就開始直接一路往下學,中途雖然有提交git,但是沒有打tag的習慣,搞的現(xiàn)在回來來寫文章有點無從下手。
不過最近應該快把diff那部分搞定了,到時候應該會加快速度更新,更多關于vue3響應式readonly的資料請關注腳本之家其它相關文章!
相關文章
使用Vue3-Ace-Editor如何在Vue3項目中集成代碼編輯器
這篇文章主要介紹了使用Vue3-Ace-Editor如何在Vue3項目中集成代碼編輯器,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
基于Vue-Cli 打包自動生成/抽離相關配置文件的實現(xiàn)方法
基于Vue-cli 項目產品部署,涉及到的交互的地址等配置信息,每次都要重新打包才能生效,極大的降低了效率。這篇文章主要介紹了基于Vue-Cli 打包自動生成/抽離相關配置文件 ,需要的朋友可以參考下2018-12-12

