Vue3响应式核心之reactive源码分析

发布时间:2023-04-25 15:41:18 作者:iii
来源:亿速云 阅读:147

Vue3响应式核心之reactive源码分析

Vue3 的响应式系统是其核心特性之一,而 reactive 是 Vue3 中用于创建响应式对象的核心 API。本文将深入分析 reactive 的源码实现,帮助读者更好地理解 Vue3 的响应式机制。

1. reactive 的基本用法

在 Vue3 中,reactive 函数用于将一个普通对象转换为响应式对象。响应式对象的属性在被访问或修改时,会自动触发依赖收集和更新。

import { reactive } from 'vue';

const state = reactive({
  count: 0,
});

state.count++; // 触发更新

2. reactive 的源码结构

reactive 的源码位于 packages/reactivity/src/reactive.ts 文件中。其主要逻辑如下:

export function reactive<T extends object>(target: T): UnwrapNestedRefs<T> {
  // 如果 target 已经是响应式对象,直接返回
  if (target && (target as any).__v_isReactive) {
    return target;
  }

  // 创建响应式对象
  return createReactiveObject(
    target,
    false,
    mutableHandlers,
    mutableCollectionHandlers,
    reactiveMap
  );
}

2.1 createReactiveObject 函数

createReactiveObjectreactive 的核心实现函数,负责创建响应式对象。其源码如下:

function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>,
  proxyMap: WeakMap<Target, any>
) {
  // 如果 target 不是对象,直接返回
  if (!isObject(target)) {
    return target;
  }

  // 如果 target 已经是 Proxy 对象,直接返回
  if (target.__v_raw && !(isReadonly && target.__v_isReactive)) {
    return target;
  }

  // 如果 target 已经有对应的 Proxy 对象,直接返回
  const existingProxy = proxyMap.get(target);
  if (existingProxy) {
    return existingProxy;
  }

  // 根据 target 的类型选择合适的 handler
  const handler = isCollectionType(target) ? collectionHandlers : baseHandlers;

  // 创建 Proxy 对象
  const proxy = new Proxy(target, handler);

  // 将 Proxy 对象存入 proxyMap
  proxyMap.set(target, proxy);

  return proxy;
}

2.2 Proxy 和 Handlers

reactive 的核心实现依赖于 ES6 的 Proxy 对象。Proxy 可以拦截对目标对象的操作,从而实现响应式。

baseHandlerscollectionHandlers 是两种不同的 Proxy 处理器,分别用于处理普通对象和集合类型(如 MapSet 等)。

2.2.1 baseHandlers

baseHandlers 是用于普通对象的处理器,其源码位于 packages/reactivity/src/baseHandlers.ts 文件中。主要逻辑如下:

export const mutableHandlers: ProxyHandler<object> = {
  get(target: Target, key: string | symbol, receiver: object) {
    // 依赖收集
    track(target, key);

    // 返回属性值
    return Reflect.get(target, key, receiver);
  },
  set(target: Target, key: string | symbol, value: any, receiver: object) {
    // 触发更新
    const result = Reflect.set(target, key, value, receiver);
    trigger(target, key);
    return result;
  },
  // 其他拦截操作...
};

2.2.2 collectionHandlers

collectionHandlers 是用于集合类型的处理器,其源码位于 packages/reactivity/src/collectionHandlers.ts 文件中。主要逻辑如下:

export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
  get(target: CollectionTypes, key: string | symbol, receiver: object) {
    // 依赖收集
    track(target, key);

    // 返回属性值
    return Reflect.get(target, key, receiver);
  },
  // 其他拦截操作...
};

3. 依赖收集与更新

Vue3 的响应式系统通过 tracktrigger 函数实现依赖收集和更新。

3.1 track 函数

track 函数用于在访问响应式对象的属性时,收集当前的依赖。其源码如下:

export function track(target: object, key: unknown) {
  if (!shouldTrack || activeEffect === undefined) {
    return;
  }

  // 获取 target 对应的依赖映射
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }

  // 获取 key 对应的依赖集合
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }

  // 将当前的 effect 添加到依赖集合中
  if (!dep.has(activeEffect)) {
    dep.add(activeEffect);
    activeEffect.deps.push(dep);
  }
}

3.2 trigger 函数

trigger 函数用于在修改响应式对象的属性时,触发依赖更新。其源码如下:

export function trigger(target: object, key: unknown) {
  // 获取 target 对应的依赖映射
  const depsMap = targetMap.get(target);
  if (!depsMap) {
    return;
  }

  // 获取 key 对应的依赖集合
  const dep = depsMap.get(key);
  if (dep) {
    // 触发依赖更新
    dep.forEach((effect) => {
      if (effect !== activeEffect) {
        effect.run();
      }
    });
  }
}

4. 总结

通过以上分析,我们可以看到 reactive 的核心实现依赖于 Proxytrack/trigger 机制。Proxy 用于拦截对目标对象的操作,而 tracktrigger 则分别用于依赖收集和更新。这种设计使得 Vue3 的响应式系统更加高效和灵活。

理解 reactive 的源码实现,不仅有助于我们更好地使用 Vue3,还能为我们设计和实现类似的响应式系统提供宝贵的参考。

推荐阅读:
  1. vue3.0新特性是什么
  2. 如何用40行代码把Vue3的响应式集成进React做状态管理

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vue3 reactive

上一篇:Vue3响应式核心之effect怎么使用

下一篇:Vue input输入框中的值怎么变成黑点

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》