本節實現響應式相關 api,包括以下vue
@vue/reactivity/src/index.tsreact
export { ref, shallowRef, toRef, toRefs } from "./ref"; export { effect } from "./effect"; export { computed } from "./computed"; export { reactive, shallowReactive, readonly, shallowReadonly, } from "./reactive";
package.jsontypescript
配置打包選項,打包出來的格式有 esm-bundler
, esm-browser
,cjs
,global
json
// package.json { "name": "@vue/reactivity", "version": "0.1.0", "main": "index.js", "buildOptions": { "name": "VueReactivity", "formats": ["esm-bundler", "esm-browser", "cjs", "global"] } }
reactive.tsapi
實現響應式 api,reactive
, shallowReactive
, readonly
,shallowReadonly
都使用 createReactiveObject 函數進行建立,該函數入參以下: target(目標對象), isReadonly(是否只讀), baseHandlers(proxy 的 handler
配置)ide
這裏將reactive
, shallowReactive
, readonly
,shallowReadonly
的 proxy 的 handler
配置所有提取到 baseHandlers.ts
文件中定義函數
import { isObject } from "@vue/shared"; import { mutableHandlers, shallowReactiveHandlers, readonlyHandlers, shallowReadonlyHandlers, } from "./baseHandlers"; export function reactive(target) { return createReactiveObject(target, false, mutableHandlers); } export function shallowReactive(target) { return createReactiveObject(target, false, shallowReactiveHandlers); } export function readonly(target) { return createReactiveObject(target, true, readonlyHandlers); } export function shallowReadonly(target) { return createReactiveObject(target, false, shallowReadonlyHandlers); } const readonlyMap = new WeakMap(); const reactiveMap = new WeakMap(); export function createReactiveObject(target, isReadonly, baseHandlers) { if (!isObject(target)) { return target; } const proxyMap = isReadonly ? readonlyMap : reactiveMap; const existProxy = proxyMap.get(target); if (existProxy) { return existProxy; } const proxy = new Proxy(target, baseHandlers); proxyMap.set(target, proxy); return proxy; }
baseHandlers.tsui
import { isObject, extend, isArray, isIntegerKey, hasOwn, hasChanged } from "@vue/shared"; import { track, trigger } from "./effect"; import { TrackOpTypes, TriggerOpTypes } from "./operations"; import { reactive, readonly } from "./reactive"; function createGetter(isReadonly = false, shallow = false) { return function get(target, key, receiver) { const res = Reflect.get(target, key, receiver); if (!isReadonly) { // 進行依賴收集 track(target, TrackOpTypes.GET, key); } if (shallow) { return res; } if (isObject(res)) { return isReadonly ? readonly(res) : reactive(res); } return res; }; } function createSetters(shallow = false) { return function set(target, key, value, receiver) { const oldValue = target[key]; const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key); const result = Reflect.set(target, key, value, receiver); if (!hadKey) { trigger(target, TriggerOpTypes.ADD, key, value); } else if (hasChanged(oldValue, value)) { trigger(target, TriggerOpTypes.SET, key, value, oldValue); } return result; }; } const get = createGetter(); const set = createSetters(); const shallowGet = createGetter(false, true); const shallowSet = createSetters(true); const readonlyGet = createGetter(true); const shallowReadonlyGet = createGetter(true, true); const readonlyObj = { set(target, key) { console.warn( `Set operation on key "${String(key)}" failed: target is readonly.`, target ); }, }; export const mutableHandlers = { get, set, }; export const shallowReactiveHandlers = { get: shallowGet, set: shallowSet, }; export const readonlyHandlers = extend( { get: readonlyGet, }, readonlyObj ); export const shallowReadonlyHandlers = extend( { get: shallowReadonlyGet, }, readonlyObj );
在 baseHandlers.ts
中 createGetter
、createSetter
函數用於建立對 reactive
, shallowReactive
, readonly
,shallowReadonly
四個 api 的 getter
和 setter
this
createGetter
函數會對訪問對象的屬性進行依賴收集,createSetter
函數會對訪問對象的屬性進行觸發更新,關於依賴收集和觸發更新咱們後續會講到設計
import { hasChanged, isArray, isObject } from "@vue/shared"; import { track, trigger } from "./effect"; import { TrackOpTypes, TriggerOpTypes } from "./operations"; import { reactive } from "./reactive"; export function ref(value) { return createRef(value); } export function shallowRef(value) { return createRef(value, true); } export function toRef(target, key) { return new ObjectRefImpl(target, key); } export function toRefs(object) { const ret = isArray(object) ? new Array(object.length) : {}; for (let key in object) { ret[key] = toRef(object, key); } return ret; } function createRef(rawValue, shallow = false) { return new RefImpl(rawValue, shallow); } const convert = (val) => (isObject(val) ? reactive(val) : val); // beta 版本 以前的版本ref 就是個對象 ,因爲對象不方便擴展 改爲了類 class RefImpl { public _value; public __v_isRef = true; constructor(public rawValue, public shallow) { // 若是是深度的,須要把裏面的變成響應式的 this._value = shallow ? rawValue : convert(rawValue); } get value() { // 依賴收集,key 爲固定的 value track(this, TrackOpTypes.GET, "value"); return this._value; } set value(newValue) { // setter,只處理 value 屬性的修改 if (hasChanged(newValue, this.rawValue)) { this.rawValue = newValue; this._value = this.shallow ? newValue : convert(newValue); // 派發通知 trigger(this, TriggerOpTypes.SET, "value", newValue); } } } class ObjectRefImpl { public __v_isRef = true; constructor(public target, public key) {} get value() { return this.target[this.key]; } set value(newValue) { this.target[this.key] = newValue; } }
ref
接受一個內部值並返回一個響應式且可變的 ref
對象。ref 對象具備指向內部值的單個 property .value
。
ref
本是用於設計對基礎類型的值進行響應式的一個 api,源碼中看到 ref 也能夠傳入一個對象,內部會對這個對象進行響應式。ref api經過調用 createRef
返回一個 RefImpl 實例,該實例上的 .value
就是 ref 函數傳入的值, 在訪問階段 getter 中會進行依賴收集,修改時會觸發依賴更新
而後 toRef
並無複用 ref 的能力(依賴收集、觸發更新),只是負責爲源響應式對象上的某個 property 新建立一個 ref。這個 ref 能夠理解爲引用,只是爲源響應式對象的 property 進行一個響應式鏈接,自身沒有響應式。
roRefs
就是複用 toRef
的能力,對一個對象的可遍歷屬性進行 toRef