完整教程:Ref 和 Reactive 响应式原理剖析与代码实现

文章目录

  • 一、概述
    • 1. 响应式核心原理
  • 二、Ref 和 Reactive对比
  • 三、 Reactive 实现原理
    • 1. 核心实现
    • 2. 完整的 reactive 实现
  • 四、 ref 实现原理
    • 1. 基础 ref 实现
    • 2. 完整的 ref 系统
  • 五、 完整的响应式系统实现
  • 六、关键点解析
  • 七、与真实 Vue 3 的差异

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

一、概述

1. 响应式核心原理

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

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

二、Ref 和 Reactive对比

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

特性refreactive
适用类型原始值 (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 响应式原理的绝佳起点。

posted on 2025-10-04 19:10  slgkaifa  阅读(5)  评论(0)    收藏  举报

导航