Vue3源码之响应式转换reactive

43 阅读1分钟

vue3中对象进行响应式转换提供了API reactive

function reactive(target) {
  // 如果是通过readonly转换的直接返回
  if (isReadonly(target)) {
    return target;
  }
  // 看下面函数内容
  return createReactiveObject(
    target,
    false,
    mutableHandlers,
    mutableCollectionHandlers,
    reactiveMap
  );
}

function createReactiveObject(
  target,
  isReadonly2,
  baseHandlers,
  collectionHandlers,
  proxyMap
) {
  if (!isObject(target)) {
      // 不是对象直接返回
    return target;
  }
  if (target["__v_raw"] && !(isReadonly2 && target["__v_isReactive"])) {
    return target;
  }
  const existingProxy = proxyMap.get(target); // 代理Map里面有,直接取返回
  if (existingProxy) {
    return existingProxy;
  }
  const targetType = getTargetType(target); // 根据类型选择相应的拦截器
  if (targetType === 0 /* INVALID */) {
    return target;
  }
  const proxy = new Proxy(
    target,
    // 区分 (数组/对象) 和 集合,来选择相应的拦截器
    targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers
  );
  proxyMap.set(target, proxy); // 代理后的值存到全局的代理prxoyMap中,方便后续用同一个target多次reactive,返回上面的同一个结果existingProxy
  return proxy;
}

来看下数组/对象的 mutableHandlers

get
const mutableHandlers = {
  get: get$1,
  set: set$1,
}

const get$1 = /* @__PURE__ */ createGetter();

function createGetter(isReadonly2 = false, shallow = false) {
  return function get2(target, key, receiver) {
   // 特殊key取值判断
    if (key === "__v_isReactive") {
      return !isReadonly2;
    } else if (key === "__v_isReadonly") {
      return isReadonly2;
    } else if (key === "__v_isShallow") {
      return shallow;
    } else if (
      key === "__v_raw" &&
      receiver ===
        (isReadonly2
          ? shallow
            ? shallowReadonlyMap
            : readonlyMap
          : shallow
          ? shallowReactiveMap
          : reactiveMap
        ).get(target)
    ) {
      return target;
    }
    const targetIsArray = isArray(target); // 数组的includes,indexOf,lastIndexOf方法进行处理
    if (!isReadonly2) {
      if (targetIsArray && hasOwn(arrayInstrumentations, key)) {
        return Reflect.get(arrayInstrumentations, key, receiver);
      }
      if (key === "hasOwnProperty") {
        return hasOwnProperty;
      }
    }
    const res = Reflect.get(target, key, receiver);
    if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
      return res;
    }
    if (!isReadonly2) {
       // 依赖收集
      track(target, "get", key);
    }
    if (shallow) {
      // 子对象不进行响应式转换
      return res;
    }
    if (isRef(res)) {
      return targetIsArray && isIntegerKey(key) ? res : res.value;
    }
    if (isObject(res)) {
       // 子对象再次进行响应式转换
      return isReadonly2 ? readonly(res) : reactive(res);
    }
    return res;
  };
}
set
const set$1 = /* @__PURE__ */ createSetter();

function createSetter(shallow = false) {
  return function set2(target, key, value, receiver) {
    let oldValue = target[key];
    if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
      return false;
    }
    if (!shallow) {
      if (!isShallow(value) && !isReadonly(value)) {
        oldValue = toRaw(oldValue);
        value = toRaw(value);
      }
      if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
        oldValue.value = value;
        return true;
      }
    }
    const hadKey =
      isArray(target) && isIntegerKey(key)
        ? Number(key) < target.length
        : hasOwn(target, key);
    const result = Reflect.set(target, key, value, receiver);
    if (target === toRaw(receiver)) {
      if (!hadKey) {
          // 依赖触发,新增key
        trigger(target, "add", key, value);
      } else if (hasChanged(value, oldValue)) {
      // 依赖触发,修改key的值
        trigger(target, "set", key, value, oldValue);
      }
    }
    return result;
  };
}

总结

  • reactive对象进行响应式转换,在get中子对象会再次进行转换
  • 同一个object多次reactive,会通过proxyMap返回同一个结果
  • 已经是响应式的再次reactive,直接返回其自身
  • get中进行依赖收集track,set中进行依赖触发trigger