vue3源码阅读(1)@vue/reactivity

120 阅读2分钟

前言

vue3也用了很久了一直说要去看源码的,一直拖到了现在,怎么说呢现在开始也不晚。

vue3的响应模块主要就是在reactive里面,reactive看懂了看其他模块也就照猫画虎了

vue3依赖于pnpm下的monorepo和ts进行源码的管理和开发,所以主要的代码包文件在packages文件夹下,对源码打包后可以在packages/vue/examples下新建文件调试,本次解析文件在packages/reactivity下

/packages/reactivity/index.ts
主要导出常用的API看源码时以此文件作为入口文件查看

reactive、readonly、shallowReactive、shallowReadonly

这四个API都基于同一个高阶函数createReactiveObject,

下面从reactive实例上进入

/packages/vue/examples下新建reactive.html右键with Live Server执行调试
<script src="../dist/vue.global.js"></script>
<div id="app"></div>
<script>
const { reactive,readonly,effect,ref } = Vue
//使用reactive声明复杂数据类型
const obj = reactive({
    name: '张三',
})
effect(() => {
    document.querySelector('#app').innerText = obj.name
})
setTimeout(() => {
  obj.name = '李四'
}, 2000)
</script>

reactive的源码/packages/reactivity/src/reactive.ts

export const reactiveMap = new WeakMap<Target, any>()
export function reactive(target:object){
    return createReactiveObject(
        target,
        false,
        mutableHandlers,// 从baseHandlers导入
        mutableCollectionHandlers,
        reactiveMap
    )
}
createReactiveObject(
    target: Target, //要代理的数据
    isReadonly: boolean, // 是否只读
    baseHandlers: ProxyHandler<any>, // Proxy代理的第二个参数,主要包含get和set
    collectionHandlers: ProxyHandler<any>,
    proxyMap: WeakMap<Target, any>, //存储以target为key value为depsMap=>(可以理解为target的key和depEffect的Map结构)的WeakMap结构
    /*baseHandlers中主要是对proxy代理数据的操作
        包含get\set\deleteProperty\has\ownKeys等操作
    */
    /*proxyMap:在实例中对应的结构
    WeakMap{
        key:obj,
        value:Map{
            key:'name',
            value:Set[Effect,Effect]
        }
    }*/
){
    // 判断是否是object
    // 判断是否已代理过
    ...
    const proxy = new Proxy(target,baseHandlers)
    proxyMap.set(target,proxy)
    return proxy
}

/packages/reactivity/src/baseHandlers.ts

export const mutableHandlers: ProxyHandler<object> = {
  get,//可拦截对象属性的访问
  set, //拦截对象属性的赋值
  deleteProperty,
  has,
  ownKeys
}
const get = /*#__PURE__*/ createGetter() // createGetter同样也是高阶函数柯里化
export const createGetter(isReadonly = false, shallow = false){
    return get(target: Target, key: string | symbol, receiver: object){
        // 一系列判断条件
        ...
        const res = Reflect.get(target, key, receiver);
        // 收集依赖
        track(target,'get',key);
        
        if(isObject(res)){//此处有优化只有在使用时才对属性做代理
            return isReadonly?readonly(res):reactive(res);
        }
        return res;
    }
}
const set = /*#__PURE__*/ createSetter()
function createSetter(shallow = false){
    return set(
        target: object,
        key: string | symbol,
        value: unknown,
        receiver: object
    ):boolean {
        let oldValue = (target as any)[key]//存储原始数据
        ....
        Reflect.set(target,key,value,receiver);
        // hasChanged数据有变化
        // 触发依赖
        trigger(target,'set',key,value,oldValue)
    }
}

走了第一步,以后的每一步都会越来越轻松