最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 探索Vue3响应式API之Ref(一)

    正文概述 掘金(lemonJW)   2021-03-21   702
    //输入
    const {ref} = VueReactivity;
    const counter = ref(0);
    console.log(counter.value);
    counter.value = 1;
    

    第一个函数:

    function ref(value) {   
     return createRef(value);
    }
    

    可以看到返回的是调用createRef(0)之后的结果,接下来看看createRef函数。

    function createRef(rawValue, shallow = false) {    
        if (isRef(rawValue)) {     
             return rawValue;   
         }    
        return new RefImpl(rawValue, shallow); 
    }
    

    这里shallow默认为false,整个函数的作用是判断rawValue是不是Ref,如果是,直接返回,否则创建新的Ref。

    如何判断传进去的值是不是已经是ref,函数如下:

     function isRef(r) {    
        return Boolean(r && r.__v_isRef === true);
     }
    

    可以看出来是通过传进去的值的__v_isRef属性,因为之前输入传的是0,0不是对象,显然返回结果为不是Ref。

    接下来看看new RefImpl发生了什么。

    class RefImpl {    
        constructor(_rawValue, _shallow = false) {      
            this._rawValue = _rawValue;     
            this._shallow = _shallow;     
            this.__v_isRef = true;      
            this._value = _shallow ? _rawValue : convert(_rawValue);    
        }   
         get value() {      ...    }   
         set value(newVal) {      ...    } 
     }
    

    RefImpl是一个类,当实例化的时候自动调用constructor内的代码,其他都好理解,这里看下convert函数干了什么。

      const convert = val => (isObject(val) ? reactive(val) : val)
    

    可以看出该函数作用是判断我们输入的值(0)是不是一个对象,是的话将对象变为响应式的,否则不做改动。

    打印看下new Reflmpl之后最终结果。

    探索Vue3响应式API之Ref(一)

    和预期的一致,接下来看下get value里面作了什么(因为之前输入打印了counter.value,所以get value里面的代码都会执行)。

    get value() {    
        track(toRaw(this), 'get' /* GET */, 'value');  
        return this._value;
    }
    

    先看toRaw。

    function toRaw(observed) {    
        return (observed && toRaw(observed['__v_raw' /* RAW */])) || observed;
    }
    

    这里用到了递归,但是因为我们传入的是普通类型0,所以并不复杂,结果没有做任何变化,返回this,再看看track。

    let shouldTrack = true;
    ...
    let activeEffect;
    ...
    function track(target, type, key) {    
        if (!shouldTrack || activeEffect === undefined) {      
            return;  
        }    
        ...
     }
    

    这里第一个判断语句直接返回,从这里就可以看出ref对普通类型做的处理很少。

    梳理一下整个过程,调用ref传0进去,会生成一个Reflmpl对象,对象内部分别挂在了__v_isRef: true,_rawValue: 1,_shallow: false,_value: 1。_rawValue和_value的值相等。

    使用对象.value时返回对象._value,其他什么也不做。很简单,对吧。

    接下来看看给.value赋值的时候会发生什么(之前counter.value = 1会触发set内的代码)。

    set value(newVal) {      
        if (hasChanged(toRaw(newVal), this._rawValue)) {        
            this._rawValue = newVal;        
            this._value = this._shallow ? newVal : convert(newVal);        
            trigger(toRaw(this), 'set' /* SET */, 'value', newVal);    
         }  
     }
    

    分别看下toRaw和hasChanged函数。

    function toRaw(observed) {    
        return (observed && toRaw(observed['__v_raw' /* RAW */])) || observed;
    }
    
    const hasChanged = (value, oldValue) => {    
        return value !== oldValue && (value === value || oldValue === oldValue);  
    }
    

    可以看出toRaw对简单类型1没有做任何改动,hasChanged比较新值1和旧值0返回true,表示值是被改变了。

    更新_rawValue和_value的值(对于简单类型直接是新值)。接下来看最后的trigger发生了什么。

    const targetMap = new WeakMap();
    ...
    function trigger(target, type, key, newValue, oldValue, oldTarget) {    
        const depsMap = targetMap.get(target);
        if (!depsMap) {      
            // never been tracked      
            return;    
        }    
        ...  
    }
    

    trigger函数又臭又长,看起来很复杂,但实际上用到部分不多(再次感叹对简单类型的处理)。这里因为targetMap里面没有数据直接return。

    总结一下,对于简单数据类型的处理,ref做的全部工作。实例化一个RefImpl对象,分别挂载__v_isRef: true,_rawValue: 变量,_shallow: false,_value: 变量 几个属性,_rawValue和_value相等。使用对象的value时,触发get,不做任何处理直接返回_value。给对象的value重新赋值时,_rawValue和_value的值同时更新(同样两个值相同)。

    简化一下整个过程:一个对象,使用对象的value,重新赋值对象的value。

    结语:

    好像又学到了点什么。


    起源地下载网 » 探索Vue3响应式API之Ref(一)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元