Vue 3 响应式原理深度解析 Vue 3 使用 Proxy 实现响应式系统,相比 Vue 2 的 Object.defineProperty 有显著优势。本文将深入解析 Vue 3 响应式原理。
一、Vue 2 vs Vue 3 1.1 Vue 2 的局限性 export class Observable { constructor (data ) { this .data = data; this .walk (data); } walk (obj ) { for (let key in obj) { let value = obj[key]; Object .defineProperty (this .data , key, { get ( ) { return value; }, set (newVal ) { value = newVal; } }); } } } const arr = reactive ({ items : [1 , 2 , 3 ] }); arr.items [0 ] = 100 ; arr.items .length = 10 ;
1.2 Vue 3 的解决方案 export function reactive (target ) { return new Proxy (target, { get (target, key ) { track (target, key); return target[key]; }, set (target, key, value ) { target[key] = value; trigger (target, key); return true ; } }); }
二、核心概念 2.1 Reactive import { reactive } from 'vue' ;const state = reactive ({ count : 0 , name : '张三' , address : { city : '北京' } }); state.count = 1 ; state.name = '李四' ; state.address .city = '上海' ;
2.2 Ref import { ref } from 'vue' ;const count = ref (0 );const name = ref ('张三' );console .log (count.value ); count.value = 1 ; const App = { setup ( ) { const count = ref (0 ); return { count }; } };
2.3 Ref vs Reactive const state = reactive ({ count : 0 , name : '张三' }); const count = ref (0 );const state = reactive ({ count : 0 });const { count } = state; const { count } = toRefs (state);
三、依赖收集系统 3.1 Effect Tracker let activeEffect = null ;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) { const dep = depsMap.get (key); dep && dep.forEach (effect => effect ()); } } function effect (fn ) { activeEffect = fn; fn (); activeEffect = null ; }
3.2 setup function setup ( ) { const count = ref (0 ); const increment = ( ) => { count.value ++; }; return { count, increment }; }
四、响应式实现 4.1 reactive 实现 export function reactive (target ) { return new Proxy (target, { get (target, key, receiver ) { track (target, key); const result = Reflect .get (target, key, receiver); return isObject (result) ? reactive (result) : result; }, 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 result = Reflect .deleteProperty (target, key); trigger (target, key); return result; } }); }
4.2 ref 实现 export function ref (value ) { if (isObject (value)) { return reactive (value); } return { _isRef : true , _value : value, get value () { track (); return this ._value ; }, set value (newValue ) { if (newValue !== this ._value ) { this ._value = newValue; trigger (); } } }; }
五、computed 5.1 computed 实现 export function computed (getter ) { let result; let dirty = true ; return { _isRef : true , get value () { if (dirty) { result = getter (); dirty = false ; } return result; }, set value (newVal ) { throw new Error ('computed ref is read-only' ); } }; }
5.2 computed setter export function computed (getter, setter ) { if (setter) { return { _isRef : true , get value () { return getter (); }, set value (newVal ) { setter (newVal); } }; } return { _isRef : true , get value () { return getter (); } }; }
六、响应式边界 6.1 reactive 解包 const state = reactive ({ count : 0 , user : { name : '张三' , age : 25 } }); const user = reactive ({ name : '李四' , age : 30 });state.user = user;
6.2 ref 解包 const count = ref (0 );const nested = ref ({ count : ref (10 ) }); nested.value .count
6.3 toRefs export function toRefs (target ) { const result = Array .isArray (target) ? [] : {}; for (const key in target) { const value = target[key]; if (isObject (value) && !isRef (value)) { result[key] = reactive (value); } else { result[key] = toRef (target, key); } } return result; } export function toRef (target, key ) { return { _isRef : true , get value () { return target[key]; }, set value (newVal ) { target[key] = newVal; } }; }
七、性能优化 7.1 shallowRef 和 shallowReactive const state = shallowRef ({ count : 0 , user : { name : '张三' } }); state.value .count = 1 ; state.value .user .name = '李四' ; const state = shallowReactive ({ count : 0 , user : { name : '张三' } }); state.count = 1 ; state.user .name = '李四' ;
7.2 markRaw import { markRaw } from 'vue' ;const rawObject = markRaw ({ data : '原始数据' }); const state = reactive ({ item : rawObject }); state.item = rawObject;
八、实战案例 8.1 状态管理 import { reactive } from 'vue' ;const store = reactive ({ user : { name : '张三' , age : 25 }, posts : [], loading : false }); function login ( ) { store.loading = true ; fetch ('/api/login' ).then (res => res.json ()).then (data => { store.user = data; store.loading = false ; }); }
8.2 表单处理 import { ref, reactive } from 'vue' ;const form = reactive ({ name : '' , email : '' , age : '' }); function handleSubmit ( ) { fetch ('/api/submit' , { method : 'POST' , headers : { 'Content-Type' : 'application/json' }, body : JSON .stringify (form) }); }
8.3 组件通信 import { reactive } from 'vue' ;const store = reactive ({ theme : 'light' , user : null }); function ThemeDisplay ( ) { return store.theme ; } function UserDisplay ( ) { return store.user ; }
九、总结 9.1 响应式系统核心 reactive - 用于对象ref - 用于基本类型computed - 计算属性依赖收集 - track触发更新 - trigger9.2 响应式边界 ref 自动解包 reactive 解包 toRefs 和 toRef 9.3 性能优化 shallowRef - 浅层响应式markRaw - 标记非响应式computed - 缓存计算结果掌握 Vue 3 响应式原理,构建高效的前端应用!