Vue reactive响应式原理解析及原生JavaScript实现方案
对,这确实是观察者模式的典型应用,Vue的响应式机制就是基于这个模式结合ES6的Proxy能力实现的。
Vue reactive 响应式机制的工作原理
Vue 3 的 reactive 函数核心逻辑可以拆成三个关键步骤:
- Proxy 代理拦截:
reactive会用Proxy对传入的原始对象做一层包装,拦截对象所有属性的**读取(get)和修改(set)**操作。比如你访问store.gender时触发get拦截器,修改它时触发set拦截器。 - 依赖自动收集:当组件渲染时,会读取store里的属性,此时
get拦截器会把当前组件的渲染函数(或者更新逻辑)记录为该属性的“依赖”,存到对应的依赖集合里。 - 触发更新通知:当你修改store的属性值时,
set拦截器会检查值是否真的变化,然后遍历该属性对应的所有依赖,调用这些依赖函数,让所有用到这个属性的组件重新渲染——这就是为什么Navigation组件会同步更新数据。
原生JavaScript实现同款响应式Store
我们可以手动用Proxy+观察者模式实现相同功能,核心是管理订阅者和触发通知:
// 简易响应式Store实现 class ReactiveStore { constructor(initialState) { // 存储订阅关系:key是属性名,value是订阅该属性的回调数组 this.subscribers = new Map(); // 用Proxy代理初始状态,拦截读写 this.state = new Proxy(initialState, { get: (target, prop) => { // 如果当前有正在执行的订阅回调,自动收集到对应属性的订阅列表 if (ReactiveStore.currentSubscriber) { if (!this.subscribers.has(prop)) { this.subscribers.set(prop, []); } this.subscribers.get(prop).push(ReactiveStore.currentSubscriber); } return target[prop]; }, set: (target, prop, value) => { // 只有值真正变化时才触发更新 if (target[prop] !== value) { target[prop] = value; // 通知所有订阅该属性的回调 if (this.subscribers.has(prop)) { this.subscribers.get(prop).forEach(callback => callback()); } } return true; } }); } // 手动订阅属性变化,传入更新回调 subscribe(prop, callback) { if (!this.subscribers.has(prop)) { this.subscribers.set(prop, []); } this.subscribers.get(prop).push(callback); // 立即执行一次回调,同步初始值 callback(); } // 静态变量,临时存储当前正在执行的订阅回调(用于自动收集依赖) static currentSubscriber = null; } // 使用示例 const store = new ReactiveStore({ gender: "", name: "" }); // 模拟Navigation组件订阅数据更新 store.subscribe('gender', () => { console.log('Navigation组件更新gender:', store.state.gender); }); store.subscribe('name', () => { console.log('Navigation组件更新name:', store.state.name); }); // 模拟RouterView修改数据 store.state.gender = 'male'; store.state.name = 'Max';
实现说明
- 自动依赖收集:通过
ReactiveStore.currentSubscriber静态变量,我们可以在组件渲染前把渲染函数赋值给它,这样组件读取store属性时就会自动被收集为依赖,不需要手动调用subscribe。 - 更新触发:当属性值变化时,
set拦截器会遍历对应订阅列表,调用所有回调函数,实现所有订阅组件的同步更新。
内容的提问来源于stack exchange,提问作者Max Pattern
相关产品推荐
相关产品推荐

