Vue3源码之响应式转换ref

60 阅读1分钟

简单类型通过ref进行响应式转换

  • 简单类型不能通过reactive转换,因为Proxy只能代理对象,vue3中提供了ref对其响应式转换

源码

ref

  • ref函数返回了createRef函数值
  • createRef函数返回了一个RefImpl类的实例
function ref(value) {
  return createRef(value, false);
}

function createRef(rawValue, shallow) {
  // 已经是ref转换后的直接返回
  if (isRef(rawValue)) {
    return rawValue;
  }
  return new RefImpl(rawValue, shallow); // 返回实例对象
}

RefImpl类

  • 通过类对精通值进行包装
  • 访问.value可以触发get value,收集依赖
  • 设置.value可以触发set value,触发依赖
// 判断是对象则使用reactive转换
const toReactive = (value) => (isObject(value) ? reactive(value) : value);

class RefImpl {
  constructor(value, __v_isShallow) {
    this.__v_isShallow = __v_isShallow;
    this.dep = void 0;
    this.__v_isRef = true; // ref的响应标识
    this._rawValue = __v_isShallow ? value : toRaw(value);
    this._value = __v_isShallow ? value : toReactive(value); // 值是对象则使用reactive转换
  }
  get value() {
    trackRefValue(this); // 依赖收集
    return this._value;
  }
  set value(newVal) {
    const useDirectValue =
      this.__v_isShallow || isShallow(newVal) || isReadonly(newVal);
      
    newVal = useDirectValue ? newVal : toRaw(newVal);
    
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal;
      this._value = useDirectValue ? newVal : toReactive(newVal);
      triggerRefValue(this, newVal); // 依赖触发
    }
  }
}