响应式系统核心是数据变化时自动触发依赖更新,通过proxy拦截读写、track/trigger实现依赖收集与通知;ref包装基础值并提供.value访问,reactive递归代理对象支持深层响应。

响应式系统的核心思想
响应式不是魔法,本质是数据变化时自动触发依赖更新。关键在于两件事:一是能“拦截”数据读写(用 Proxy);二是能“记住”谁在读这个数据(依赖收集),并在写时通知它(触发更新)。
ref 的实现:包装基础值,提供 .value 访问
ref 用于包装原始类型(如字符串、数字)或简单对象,让它具备响应式能力。核心是返回一个带 get/set 的 reactive 对象,并内置依赖追踪逻辑。
代码如下:
let activeEffect = null;
function effect(fn) {
activeEffect = fn;
fn(); // 执行一次,触发依赖收集
activeEffect = null;
}
const targetMap = new WeakMap();
function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
depsMap = new Map();
targetMap.set(target, depsMap);
}
let dep = depsMap.get(key);
if (!dep) {
dep = new Set();
depsMap.set(key, dep);
}
dep.add(activeEffect);
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const effects = depsMap.get(key);
if (effects) {
effects.forEach(effect => effect());
}
}
function ref(raw) {
const r = {
_raw: raw,
_value: raw,
get value() {
track(r, 'value');
return r._value;
},
set value(newVal) {
if (newVal !== r._value) {
r._value = newVal;
trigger(r, 'value');
}
}
};
return r;
}
reactive 的实现:递归代理对象,支持深层响应
reactive 用于包装对象,返回一个 Proxy,对所有属性的读写进行拦截。重点是:读取时收集依赖,设置时触发更新,且对嵌套对象自动递归 reactive。
代码如下:
function reactive(obj) {
if (typeof obj !== 'object' || obj === null) return obj;
const handler = {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver);
track(target, key); // 收集依赖
// 深响应:对对象属性自动 reactive
if (typeof res === 'object' && res !== null) {
return reactive(res);
}
return res;
},
set(target, key, value, receiver) {
const oldVal = target[key];
const res = Reflect.set(target, key, value, receiver);
if (oldVal !== value) {
trigger(target, key); // 触发更新
}
return res;
}
};
return new Proxy(obj, handler);
}
组合使用与注意事项
你可以这样用:
const state = reactive({ count: 0 });
const countRef = ref(10);
effect(() => {
console.log('count:', state.count); // 响应式读取
console.log('ref value:', countRef.value); // 通过 .value 读取
});
state.count++; // 自动触发 effect
countRef.value = 20; // 自动触发 effect
- 不要直接解构 ref:`const { value } = ref(1)` 会丢失响应性,必须始终通过 `.value` 访问
- reactive 不处理原始类型:传入数字或字符串会直接返回原值,不代理
- 避免循环引用:Proxy 无法代理自身,递归 reactive 时需加判断防止栈溢出(生产版需增强)
- effect 是简易副作用函数,真实 Vue 还有调度、清理、嵌套等机制,这里只保留最简链路











