4.Vue3计算属性computed实现原理

发布时间:2023-07-28 10:30

computed实现原理

computed特性

computed可以传入一个函数,也可以传入一个对象(带有get和set方法),计算属性返回一个计算值,该值通过value属性访问,当参与计算的数据发生改变,则重新计算,不发生改变,则直接返回之前缓存的值

  • render 只执行了一次
   const { effect, reactive,computed } = VueReactivity

        const state = reactive({
            firstName:\'s\',
            lastName:\'x\'
        })
        let fullName = computed(()=>{
            console.log(\'runner\')
            return state.firstName + state.lastName
        })
        console.log(fullName.value)
        console.log(fullName.value)
        console.log(fullName.value)

计算属性返回值可以作为属性参与effect更新

 const { effect, reactive,computed } = VueReactivity

        const state = reactive({
            firstName:\'s\',
            lastName:\'x\'
        })
       
        let fullName = computed({
            get(){
                return state.firstName + state.lastName
            },
            set(value){
                state.lastName = value
            }
        })
        fullName.value = 100
        effect(()=>{
            app.innerHTML = fullName.value
        })
        setTimeout(()=>{
            state.firstName = \'x\'
        },1000)

实现思路

  • 导出一个computed函数,函数内部有两个变量getter、setter
  • 函数传入一个对象或者函数。
  • 如果是函数,则将该函数赋值给getter,setter赋值为一个报错函数(即抛出错误)
  • 如果是对象,则将其get和set分别赋值给getter和setter
  • 创建computedRefImpl类,有两个形参(getter、setter),在computer函数中实例化并返回该类
  • 类中在实例的constructor构造器中通过实例化ReactiveEffect类,传入getter,实现对计算属性函数传入的属性的数据绑定,传入第二个参数,在数据更新完之后将_dirty标记为true,并实现数据更新(triggerEffects)
  • 私有变量_dirty控制数据是否更新
  • 其有两个方法get value 和 set value
  • 当调用get,让ReactiveEffect实例运行,获取其返回值赋值给内部变量_value,并返回改变量,将_dirty设置为false,表示没有新的数据改变了,可以使用缓存,判断当前环境是否存在activeEffect,存在则进行依赖收集(调用trackEffects)
  • 调用set则运行setter

完整代码如下:

import { isFunction } from \"@vue/shared\"
import { activeEffect, trackEffects, triggerEffects,ReactiveEffect } from \"./effect\";

export function computed(getterOrOptions){
    let getter = null;
    let setter = null;
    let fn = ()=>{
        throw new Error(\"this function is onlyRead\");
        
    }
    let isGetter = isFunction(getterOrOptions)
    if(isGetter){
        getter = getterOrOptions
        setter = fn
    }
    else {
        getter = getterOrOptions.get
        setter = getterOrOptions.set || fn
    }

    return new computedRefImpl(getter,setter)
}

class computedRefImpl{
    private _value = null
    private _dirty = true
    public effect = null
    public deps = null
    constructor(getter,public setter){
        this.effect = new ReactiveEffect(getter,()=>{
            if(!this._dirty){
                this._dirty = true
                triggerEffects(this.deps)
            }
        })
    }
    get value(){
        debugger
        if(activeEffect){
            // 存在effect,则进行依赖收集
            trackEffects(this.deps ||  (this.deps = new Set()) )
        }
        if(this._dirty){
            this._dirty = false
            this._value = this.effect.run()
        }
        return this._value
    }
    set value(newValue){
        this.setter(newValue)
    }
}

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号