vue3源码分析:响应式原理
2026-08-07 16:40:25
模仿vue3 实现最简单的响应式系统
入口文件:index.js
import {reactive} from "./reactive.js"
import {effect} from "./effect.js"
const state = reactive({
count: 1,
})
//对应源码中componentUpdateFn函数,简化方法体,响应式数据被访问时,可触发 依赖收集 即可
const componentUpdateFn = ()=>{
console.log("count:", state.count)
}
effect(componentUpdateFn)
state.count = 3
reactive.js
import {track, trigger} from "./dep.js"
const reactiveMap = new WeakMap();//存储 原始对象=>响应式代理对象 映射关系
export function reactive(target) {
//将要代理的数据必须是对象
if(typeof target !== 'object'|| target === null) {
return target
}
const existingTarget = reactiveMap.get(target)
if(existingTarget) {
return existingTarget
}
const proxy = new Proxy(target, {
get(target, key,receiver) {
const result = Reflect.get(target, key,receiver)
// 收集依赖
console.log('收集依赖')
track(target, key)
return result;
},
set(target, key, value,receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value,receiver);
if(oldValue !== value) {
// 通知更新
console.log('通知更新')
trigger(target, key);
}
return result;
},
})
reactiveMap.set(target, proxy)
return proxy;
}
effect.js
export let activeEffect = undefined
export class ReactiveEffect {
fn;
deps = [];
constructor(fn) {
this.fn = fn;
}
run(){
activeEffect = this;
const result = this.fn();
activeEffect = undefined;
return result;
}
}
export function effect(fn){
const reactiveEffect = new ReactiveEffect(fn);
const update = reactiveEffect.run.bind(reactiveEffect);
update();
}
dep.js
import {activeEffect,} from "./effect.js"
const targetMap = new WeakMap()
export class Dep {
subscribers = new Set()
track(){
if(!activeEffect){
return
}
// 已经存在不重复添加
if(!this.subscribers.has(activeEffect)){
this.subscribers.add(
activeEffect
)
// 反向记录
activeEffect.deps.push(
this
)
}
}
trigger(){
this.subscribers.forEach(
effect=>{
effect.run()
}
)
}
}
// 收集依赖
export 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 Dep()
depsMap.set(key, dep)
}
dep.track()
}
//通知更新
export function trigger(target, key){
const depsMap =targetMap.get(target)
if(!depsMap){
return
}
const dep =depsMap.get(key)
if(dep){
dep.trigger()
}
}
测试:
node index.js
结果:
收集依赖
count: 1
通知更新
收集依赖
count: 3