Ref 和 Reactive 响应式原理剖析与代码实现

简介: 本文深入剖析 Vue 3 响应式核心原理,详解 `ref` 与 `reactive` 的区别与实现机制。通过手写简化版响应式系统,揭示基于 Proxy 的依赖收集、触发更新、自动解包等关键逻辑,助你掌握 Composition API 的底层思想。(238 字)

@TOC
好的,我们来深入剖析 Vue 3 中 refreactive 的核心原理,并手写一个简化但能体现核心思想的实现。

一、概述

1. 响应式核心原理

Vue3 的响应式系统基于 ES6 的 Proxy 实现,相比 Vue2 的 Object.defineProperty 有以下优势:

  • 可以监听数组变化
  • 可以监听对象属性的添加和删除
  • 性能更好

二、Ref 和 Reactive对比

以下是 refreactive的核心概念与区别

特性 ref reactive
适用类型 原始值 (number, string, boolean) 和 对象 仅对象 (包括数组、Map、Set 等复杂类型)
访问方式 .value 访问/修改值 直接访问/修改属性
底层实现 包装成一个带有 .value 属性的对象,用 Proxy 拦截 .value 的读写 直接用 Proxy 包装目标对象本身
解构问题 解构会失去响应性 解构会失去响应性 (... 扩展运算符也会)
内部转换 reactive 内部如果遇到 ref,会自动解包 (unwrap)

三、 Reactive 实现原理

1. 核心实现

// 响应式处理
function reactive(target) {
   
  return createReactiveObject(target);
}

// 创建响应式对象
function createReactiveObject(target) {
   
  // 如果不是对象,直接返回
  if (typeof target !== 'object' || target === null) {
   
    return target;
  }

  // 如果已经是代理对象,直接返回
  if (target.__v_isReactive) {
   
    return target;
  }

  const proxy = new Proxy(target, {
   
    get(target, key, receiver) {
   
      // 内置属性标识
      if (key === '__v_isReactive') {
   
        return true;
      }

      const res = Reflect.get(target, key, receiver);

      // 依赖收集
      track(target, key);

      // 递归处理嵌套对象
      return isObject(res) ? reactive(res) : res;
    },

    set(target, key, value, receiver) {
   
      const oldValue = target[key];
      const result = Reflect.set(target, key, value, receiver);

      // 触发更新
      if (oldValue !== value) {
   
        trigger(target, key);
      }

      return result;
    },

    deleteProperty(target, key) {
   
      const hadKey = hasOwn(target, key);
      const result = Reflect.deleteProperty(target, key);

      if (hadKey && result) {
   
        trigger(target, key);
      }

      return result;
    }
  });

  return proxy;
}

// 工具函数
function isObject(val) {
   
  return val !== null && typeof val === 'object';
}

function hasOwn(target, key) {
   
  return Object.prototype.hasOwnProperty.call(target, key);
}

2. 完整的 reactive 实现

// 依赖收集和触发
const targetMap = new WeakMap();
let activeEffect = null;

function track(target, key) {
   
  if (!activeEffect) return;

  let depsMap = targetMap.get(target);
  if (!depsMap) {
   
    targetMap.set(target, (depsMap = new Map()));
  }

  let dep = depsMap.get(key);
  if (!dep) {
   
    depsMap.set(key, (dep = new Set()));
  }

  dep.add(activeEffect);
}

function trigger(target, key) {
   
  const depsMap = targetMap.get(target);
  if (!depsMap) return;

  const dep = depsMap.get(key);
  if (dep) {
   
    dep.forEach(effect => effect());
  }
}

// 完整的 reactive 函数
function reactive(target) {
   
  if (!isObject(target)) {
   
    console.warn(`value cannot be made reactive: ${
     String(target)}`);
    return target;
  }

  if (target.__v_isReactive) {
   
    return target;
  }

  const handler = {
   
    get(target, key, receiver) {
   
      if (key === '__v_isReactive') {
   
        return true;
      }

      const res = Reflect.get(target, key, receiver);
      track(target, key);

      return isObject(res) ? reactive(res) : res;
    },

    set(target, key, value, receiver) {
   
      const oldValue = target[key];
      const result = Reflect.set(target, key, value, receiver);

      if (oldValue !== value) {
   
        trigger(target, key);
      }

      return result;
    },

    deleteProperty(target, key) {
   
      const hadKey = hasOwn(target, key);
      const result = Reflect.deleteProperty(target, key);

      if (hadKey && result) {
   
        trigger(target, key);
      }

      return result;
    }
  };

  return new Proxy(target, handler);
}

四、 ref 实现原理

1. 基础 ref 实现

function ref(value) {
   
  return createRef(value);
}

function createRef(rawValue) {
   
  // 如果已经是 ref,直接返回
  if (isRef(rawValue)) {
   
    return rawValue;
  }

  return new RefImpl(rawValue);
}

class RefImpl {
   
  constructor(value) {
   
    this.__v_isRef = true;
    this._value = isObject(value) ? reactive(value) : value;
    this.dep = new Set();
  }

  get value() {
   
    trackRefValue(this);
    return this._value;
  }

  set value(newVal) {
   
    if (newVal !== this._value) {
   
      this._value = isObject(newVal) ? reactive(newVal) : newVal;
      triggerRefValue(this);
    }
  }
}

function isRef(r) {
   
  return !!(r && r.__v_isRef === true);
}

function trackRefValue(ref) {
   
  if (activeEffect) {
   
    ref.dep.add(activeEffect);
  }
}

function triggerRefValue(ref) {
   
  ref.dep.forEach(effect => effect());
}

2. 完整的 ref 系统

// 完整的 ref 实现
class RefImpl {
   
  constructor(value) {
   
    this.__v_isRef = true;
    this._rawValue = value;
    this._value = convert(value);
    this.dep = new Set();
  }

  get value() {
   
    trackRefValue(this);
    return this._value;
  }

  set value(newVal) {
   
    if (hasChanged(newVal, this._rawValue)) {
   
      this._rawValue = newVal;
      this._value = convert(newVal);
      triggerRefValue(this);
    }
  }
}

// 工具函数
function convert(val) {
   
  return isObject(val) ? reactive(val) : val;
}

function hasChanged(value, oldValue) {
   
  return !Object.is(value, oldValue);
}

function ref(value) {
   
  return createRef(value, false);
}

function createRef(rawValue, shallow) {
   
  if (isRef(rawValue)) {
   
    return rawValue;
  }
  return new RefImpl(rawValue);
}

// 自动解构 ref
function unref(ref) {
   
  return isRef(ref) ? ref.value : ref;
}

// 在模板中自动解构
function proxyRefs(objectWithRefs) {
   
  return new Proxy(objectWithRefs, {
   
    get(target, key, receiver) {
   
      return 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);
      }
    }
  });
}

五、 完整的响应式系统实现

// 完整的响应式系统
class ReactiveEffect {
   
  constructor(fn) {
   
    this.fn = fn;
  }

  run() {
   
    activeEffect = this;
    return this.fn();
  }
}

function effect(fn) {
   
  const _effect = new ReactiveEffect(fn);
  _effect.run();
  return _effect;
}

// 响应式系统核心
const reactiveMap = new WeakMap();

function reactive(target) {
   
  const existingProxy = reactiveMap.get(target);
  if (existingProxy) {
   
    return existingProxy;
  }

  const proxy = createReactiveObject(
    target,
    baseHandlers,
    collectionHandlers
  );

  reactiveMap.set(target, proxy);
  return proxy;
}

const baseHandlers = {
   
  get(target, key, receiver) {
   
    if (key === '__v_isReactive') return true;

    const res = Reflect.get(target, key, receiver);
    track(target, key);

    if (isObject(res)) {
   
      return reactive(res);
    }

    return res;
  },

  set(target, key, value, receiver) {
   
    const oldValue = target[key];
    const result = Reflect.set(target, key, value, receiver);

    if (hasChanged(value, oldValue)) {
   
      trigger(target, key);
    }

    return result;
  },

  deleteProperty(target, key) {
   
    const hadKey = hasOwn(target, key);
    const result = Reflect.deleteProperty(target, key);

    if (hadKey && result) {
   
      trigger(target, key);
    }

    return result;
  }
};

// 测试用例
function testReactiveSystem() {
   
  console.log('=== Testing Reactive System ===');

  // 测试 reactive
  const state = reactive({
    count: 0, user: {
    name: 'John' } });

  effect(() => {
   
    console.log('Count changed:', state.count);
  });

  effect(() => {
   
    console.log('User name:', state.user.name);
  });

  state.count = 1;
  state.user.name = 'Jane';

  // 测试 ref
  const count = ref(0);

  effect(() => {
   
    console.log('Ref count:', count.value);
  });

  count.value = 10;
}

// 运行测试
testReactiveSystem();

六、关键点解析

  1. ref 的本质

    • 它是一个对象,这个对象有一个 .value 属性。
    • 我们对 .value 的读写进行拦截,从而让原始值具备了响应性。
    • __v_isRef 是一个标志位,告诉 reactive 系统“这是一个 ref,请在访问时自动解包”。
  2. reactive 的深度响应式

    • get 拦截器中,如果发现获取的值是一个对象,会递归调用 reactive,确保嵌套对象也是响应式的。
  3. 自动解包 (Auto-unwrapping)

    • ref 被放入 reactive 对象中时,在模板或 effect 中访问 user.age 时,reactiveget 拦截器检测到 age 是一个 ref(通过 __v_isRef),于是返回 age.value,实现了自动解包。这是 Vue 3 模板语法简洁的关键。
  4. computed 的惰性求值

    • computed 返回的也是一个 ref
    • 它内部有一个 dirty 标志位,只有当依赖的数据变化时才标记为脏。
    • 只有当有人读取 .valuedirtytrue 时,才会重新执行 getter 函数。

七、与真实 Vue 3 的差异

  • 性能优化:真实的 trigger 有更复杂的调度机制(queueJob)和 flush 时机(pre, post, sync)。
  • 边界情况:真实实现处理了 Symbolin 操作符、has 拦截器、数组索引变化等。
  • shallowReactive / shallowRef:浅层响应式。
  • toRefs:解决解构失去响应性的问题。
  • readonly:只读代理。
  • effectScope:副作用作用域管理。

这个手写版本虽然简化,但已经完整地体现了 refreactive 的核心设计思想和交互逻辑,是理解 Vue 3 Composition API 响应式原理的绝佳起点。

相关文章
|
21天前
|
XML Android开发 数据格式
Android setContentView源码与原理分析
`setContentView` 是 Activity 显示界面的核心方法,其本质是将布局嵌入由 `PhoneWindow` 管理的 `DecorView` 中。系统首先创建包含状态栏、标题栏等的窗口模板(如 `screen_simple.xml`),再通过 `LayoutInflater` 将开发者指定的布局加载到 ID 为 `android.R.id.content` 的 `mContentParent` 容器内,最终在 `Activity` 恢复时由 `WindowManager` 将 `DecorView` 添加至窗口,触发测量与绘制流程,完成界面显示。
178 73
|
19天前
|
Dart 开发工具 Android开发
Flutter PC 应用开发指南:从环境搭建到实战避坑
本文系统介绍如何在 Windows 平台使用 Flutter 开发 PC 应用,涵盖环境搭建、项目创建、插件兼容性、原生功能调用、签名发布、常见问题解决及性能优化等全流程,助你高效构建跨平台桌面应用,少走弯路。
374 5
|
21天前
|
安全 算法 Java
Android APK签名机制的工作原理、结构差异、安全局限与优势
本文深入解析Android APK的v1与v2签名机制,涵盖工作原理、结构差异、安全局限及最佳实践。详述身份认证、完整性保护等核心目标,对比各版本优劣,并提供签名生成、验证流程与生产环境建议,助力开发者构建安全可信的应用。
345 1
|
21天前
|
缓存 安全 API
android studio Gradle 打包任务配置
本文详解Android Studio中AGP自动生成的Gradle打包任务机制,涵盖`build.gradle`核心配置:签名管理、多渠道构建、APK/AAB输出命名,以及CI/CD集成技巧。系统梳理打包流程,提供安全、高效、可追溯的发布实践方案。(238字)
248 0
|
21天前
|
SQL 人工智能 自然语言处理
Navicat AI 助理实战指南:开启智能数据库管理新时代
Navicat集成AI助理,支持自然语言生成SQL、智能优化与错误诊断。通过云端或本地模型(如Ollama)实现高效安全的数据库管理,提升开发效率60%以上,助力开发者迈向智能工作流新时代。
140 0
|
21天前
|
存储 负载均衡 安全
HashMap 源码及原理解析
HashMap是Java核心数据结构,基于哈希表实现键值对存储。JDK 1.8采用数组+链表/红黑树结构,通过哈希计算定位元素,链表过长时转为红黑树以提升性能。支持null键值,非线程安全。核心机制包括哈希扰动、扩容重哈希(2倍扩容)、负载因子(默认0.75)及树化阈值(8),确保高效存取与动态平衡。
70 1
|
JSON Java 数据格式
一文彻底搞懂 @RequestBody 和 @RequestParam 的区别(附实战示例)
本文深入解析Spring Boot中@RequestBody和@RequestParam的区别,通过实战示例详解两者在数据来源、格式、使用场景及验证处理上的差异,帮助开发者正确选择参数绑定方式,提升开发效率与系统安全性。
465 0
|
21天前
|
XML Android开发 数据格式
Android Jetpack Compose 从入门到精通
Jetpack Compose 是 Google 推出的现代化 Android 声明式 UI 框架,基于 Kotlin,简化传统 XML 开发。本教程系统讲解其核心概念:可组合函数、状态管理、布局系统、Modifier 修饰符、列表滚动、主题样式、导航与动画等,助你高效构建响应式、高性能应用界面,掌握从入门到高级的最佳实践与技巧。
191 0
|
2月前
|
人工智能 弹性计算 安全
阿里云无影云电脑具体价格:个人版、企业版和免费云电脑配置介绍
阿里云无影云电脑2025年最新价格:企业版4核8G低至199元/年,支持办公与设计;个人版分黄金到黑金多款,月费14元起,适配云游戏与AI办公。含GPU高配机型,另享免费试用。
|
人工智能 监控 数据可视化
绩效考核管理的动态调整与持续优化
本文探讨了绩效考核管理在现代企业管理中的重要性,从核心原则、流程设计、指标设定、沟通反馈及持续优化五个方面进行了详细阐述,并推荐了板栗看板作为提升绩效管理效率的工具。文章强调了公平公正、客观量化、战略导向、持续反馈和结果应用的原则,以及平衡计分卡、KPI、OKR和360度反馈等多种考核方法的应用。板栗看板以其强大的可视化、动态追踪、高效沟通和数据分析功能,助力企业实现高效的绩效管理。