返回

Vue 3响应式系统的核心——Reactive源码详解

前端

一、响应式系统的核心:Reactive源码

Vue 3的响应式系统是基于ES6 Proxy实现的,它允许我们对对象进行监听,以便在数据发生变化时触发更新。响应式系统的核心函数是reactive,它接受一个对象作为参数,并返回一个响应式代理对象。

1、reactive 源码路径:packages/reactivity/src/reactive.ts

当我们执行reactive({})的时候,会执行createReactiveObject函数,该函数会根据传入的对象类型创建不同的响应式代理对象。

2、createReactiveObject函数源码解析

export function createReactiveObject(target: any, isShallow: boolean, wrap: ReactiveFlags = null) {
  // 如果目标对象是对象,则创建响应式代理对象
  if (isPlainObject(target)) {
    return new Proxy(target, proxyHandlers);
  }
  // 如果目标对象是数组,则创建响应式数组
  else if (Array.isArray(target)) {
    return createArrayProxy(target, isShallow);
  }
  // 如果目标对象是其他类型,则直接返回目标对象
  else {
    return target;
  }
}

从源码中可以看出,createReactiveObject函数会根据传入对象的类型创建不同的响应式代理对象。对于对象,它会创建响应式代理对象;对于数组,它会创建响应式数组;对于其他类型的数据,它会直接返回目标对象。

3、proxyHandlers源码解析

const proxyHandlers: ProxyHandler<object> = {
  // 当读取响应式对象的属性时触发
  get(target: object, key: string | symbol): any {
    // 如果属性是特殊属性,则直接返回属性值
    if (isBuiltInAccessor(key)) {
      return target[key];
    }
    // 如果属性是响应式对象的key,则返回key对应的响应式值
    else if (key === ReactiveFlags.IS_REACTIVE) {
      return true;
    }
    // 如果属性不存在,则返回undefined
    else if (!target.hasOwnProperty(key)) {
      return undefined;
    }
    // 如果属性存在,则返回属性对应的响应式值
    else {
      // track函数用于追踪依赖关系
      track(target, TrackOpTypes.GET, key);
      return Reflect.get(target, key);
    }
  },
  // 当设置响应式对象的属性时触发
  set(target: object, key: string | symbol, value: any): boolean {
    // 如果属性是特殊属性,则直接设置属性值
    if (isBuiltInAccessor(key)) {
      target[key] = value;
      return true;
    }
    // 如果属性不存在,则添加属性并设置属性值
    else if (!target.hasOwnProperty(key)) {
      target[key] = value;
      // trigger函数用于触发更新
      trigger(target, TriggerOpTypes.ADD, key, value);
      return true;
    }
    // 如果属性存在,则设置属性值并触发更新
    else {
      const oldValue = target[key];
      target[key] = value;
      // trigger函数用于触发更新
      trigger(target, TriggerOpTypes.SET, key, value, oldValue);
      return true;
    }
  },
  // 当删除响应式对象的属性时触发
  deleteProperty(target: object, key: string | symbol): boolean {
    // 如果属性是特殊属性,则直接删除属性
    if (isBuiltInAccessor(key)) {
      delete target[key];
      return true;
    }
    // 如果属性存在,则删除属性并触发更新
    else if (Reflect.has(target, key)) {
      delete target[key];
      // trigger函数用于触发更新
      trigger(target, TriggerOpTypes.DELETE, key);
      return true;
    }
    // 如果属性不存在,则直接返回false
    else {
      return false;
    }
  }
};

从源码中可以看出,proxyHandlers是一个代理处理程序,它实现了响应式对象的get、set和deleteProperty方法。

4、track函数源码解析

export function track(target: object, type: TrackOpTypes, key: string | symbol) {
  // 如果当前处于依赖收集阶段,则将依赖关系添加到当前依赖收集器中
  if (activeEffect) {
    activeEffect.recordEffect(target, type, key);
  }
}

从源码中可以看出,track函数的作用是将依赖关系添加到当前依赖收集器中。

5、trigger函数源码解析

export function trigger(
  target: object,
  type: TriggerOpTypes,
  key: string | symbol,
  newValue?: any,
  oldValue?: any
) {
  // 获取响应式对象的依赖收集器列表
  const depsMap = targetMap.get(target);
  // 如果依赖收集器列表存在,则遍历依赖收集器列表并触发更新
  if (depsMap) {
    const effects = depsMap.get(key);
    if (effects) {
      effects.forEach((effect) => {
        if (effect !== activeEffect) {
          effect();
        }
      });
    }
  }
}

从源码中可以看出,trigger函数的作用是触发响应式对象的更新。

二、如何利用响应式系统构建强大的Vue 3应用程序

Vue 3的响应式系统为我们提供了一种简单而强大的方式来构建响应式应用程序。我们可以利用响应式系统来实现以下功能:

1、数据绑定

响应式系统可以实现数据绑定,即当数据发生变化时,界面会自动更新。这使我们能够轻松地构建交互式的用户界面。

2、状态管理

响应式系统可以实现状态管理,即我们可以将应用程序的状态存储在响应式对象中,并在应用程序中使用响应式对象来访问和更新状态。这使我们能够轻松地管理应用程序的状态,并使应用程序更加易于维护。

3、组件通信

响应式系统可以实现组件通信,即我们可以通过响应式对象在组件之间传递数据。这使我们能够轻松地构建复杂的应用程序,并使组件之间能够相互通信。

三、总结

Vue 3的响应式系统是一个简单而强大的工具,我们可以利用它来构建响应式应用程序。响应式系统可以实现数据绑定、状态管理和组件通信,这使我们能够轻松地构建交互式的、易于维护的和可扩展的应用程序。