vue3 响应式随笔

155 阅读1分钟
认识ref shallowRef triggerRef
  1. 用法
<template>
  <div>{{mycount}}
  <button @click="changeMyCount">111</button>
  </div>
</template>

<script>

import { ref,shallowRef,triggerRef } from "vue";
export default {
  name: "ref",
  setup(){
      // ref 分为两种情况  ref(2) ref({datas:2}) 这两种情况是不一样的
    const mycount = ref(2);
    //shallowRef 创建的值 是只做第一层的响应,就是像vue2 中的数据响应,对于对象内的变动,是不是响应的
    // triggerRef 强制刷新视图 
    const changeMyCount = ()=>{
    mycount.value.kk = mycount.value.kk + 2 ;
    dd.value.age = dd.value.age + 4 ;
    triggerRef(dd)
    }

    return {
      mycount,
      changeMyCount,
    }
  }
}

</script>

<style>
  .a {
    background: red;
  }
</style>
  1. 尝试阅读源码,下载cdn文件去查看。《我之前的地址》
// 1
function ref(value) {
    console.log(1,value)
    return createRef(value, false);
}
// 2
function createRef(rawValue, shallow) {
    if (isRef(rawValue)) {
        return rawValue;
    }
    return new RefImpl(rawValue, shallow);
}
//3

class RefImpl {
    constructor(value, _shallow) {
        this._shallow = _shallow;// 浅监听
        this.dep = undefined;
        this.__v_isRef = true; // 对应了上面 isRef(rawValue)
        // 原始value
        this._rawValue = _shallow ? value : toRaw(value);
        // 实际用到的value
        this._value = _shallow ? value : toReactive(value);

    }
    get value() {
        trackRefValue(this);
        return this._value;
    }
    set value(newVal) {
        newVal = this._shallow ? newVal : toRaw(newVal);
        if (hasChanged(newVal, this._rawValue)) {
            this._rawValue = newVal;
            this._value = this._shallow ? newVal : toReactive(newVal);
            triggerRefValue(this, newVal);
        }
    }
}

接下来来看下get 里面都干了啥

// dep 跟 reactive 响应有关系, 可以先不管。目前只需要判断dep是否为undefined
const createDep = (effects) => {
    const dep = new Set(effects);
    dep.w = 0;
    dep.n = 0;
    return dep;
};
//
let shouldTrack = true;

let activeEffect;

function isTracking() {
    return shouldTrack && activeEffect !== undefined;
}

// 
function trackRefValue(ref) {
    if (isTracking()) {
        ref = toRaw(ref);
        if (!ref.dep) {
            ref.dep = createDep();
        }
        {
        // 响应监听value的变化,先不深究这个方法。
            trackEffects(ref.dep, {
                target: ref,
                type: "get" /* GET */,
                key: 'value'
            });
        }
    }
}

现在再来看下set 方法

// reactive === import {reactive} from 'vue'

const toReactive = (value) => isObject(value) ? reactive(value) : value;


set value(newVal) {
    newVal = this._shallow ? newVal : toRaw(newVal);
    // 值是否变动
    if (hasChanged(newVal, this._rawValue)) {
        this._rawValue = newVal;
        // set 值之后。避免value变为对象失去监听
        this._value = this._shallow ? newVal : toReactive(newVal);
        // 触发器 触发 调度器 ,产生页面更新
        triggerRefValue(this, newVal);
    }
}

所以现在敲重点 记笔记。 ref 数据响应式分为两种。一种是对象类型,另外一种是非对象类型。处理方式是不一样的,不是全部proxy 一把梭哈。对于非对象类型还是采用原有的Object.defineProperty 监听方式, 对于传入的对象则是采用 proxy 监听。 然你后在 proxy 去 触发调度器,然后刷新到视图。