面试官: Vue3中的ref,模版里面为什么不用.value就能取到值

248 阅读1分钟

在渲染之前,会取setup的返回结果,挂到VNode上,具体看下代码:

function handleSetupResult(instance, setupResult, isSSR) {
  if (isFunction(setupResult)) {
    {
      instance.render = setupResult;
    }
  } else if (isObject(setupResult)) {
    if (isVNode(setupResult)) {
      warn(
        `setup() should not return VNodes directly - return a render function instead.`
      );
    }
    // 重点
    instance.setupState = proxyRefs(setupResult); // 取setup函数返回值
    
  } else if (setupResult !== void 0) {
    warn(
      `setup() should return an object. Received: ${
        setupResult === null ? "null" : typeof setupResult
      }`
    );
  }
  finishComponentSetup(instance, isSSR);
}

proxyRefs(setupResult)结果用proxyRefs进行了处理,看下proxyRefs函数:

function proxyRefs(objectWithRefs) {
  return isReactive(objectWithRefs)
    ? objectWithRefs
    : new Proxy(objectWithRefs, shallowUnwrapHandlers); // 使用了Proxy进行一层拦截代理
}

const shallowUnwrapHandlers = {
  // 在模版中进行取值时,会走get,进而走unref方法
  get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)),
  set: (target, key, value, receiver) => {
    const oldValue = target[key];
    if (isRef(oldValue) && !isRef(value)) {
      oldValue.value = value;
      return true;
    } else {
      return Reflect.set(target, key, value, receiver);
    }
  },
};

unref里面代码

function unref(ref2) {
   // 在模版里面取值,会通过代理拦截走到这里
   // 判断是不是ref转换的,是返回.value,不是返回自身
  return isRef(ref2) ? ref2.value : ref2;
}
// 判断是不是用ref转换的
function isRef(r) {
  return !!(r && r.__v_isRef === true);
}

结论

  • 模版里面数据,来自setup函数返回的结果
  • setup返回结果,通过proxyRefs进行了拦截代理
  • 最终,取值会走拦截器get,通过unref自动取value的值