Principles of Vue3 Reactive System
Description
Vue3's reactive system is its core mechanism, capable of automatically tracking data dependencies and triggering updates to relevant components when data changes. This system is implemented based on ES6's Proxy and Reflect APIs, offering more powerful features and better performance compared to Vue2's Object.defineProperty.
Solution Process
-
Core Objective Analysis
- We need to establish a system that can record "who is reading it" (dependency collection) when data is read.
- When data is modified, it can notify "all places that have read it" to update (dependency triggering).
-
Basic Implementation Principles
- Use Proxy to intercept get/set operations on the target object.
- Use WeakMap, Map, and Set to build a dependency relationship graph.
- Establish reactive dependencies through the effect function.
-
Detailed Implementation Steps
Step 1: Create Reactive Object
function reactive(target) { return new Proxy(target, { get(obj, key) { // Dependency collection: Record the currently executing effect track(obj, key) return Reflect.get(obj, key) }, set(obj, key, value) { const result = Reflect.set(obj, key, value) // Dependency triggering: Notify all effects that depend on this property trigger(obj, key) return result } }) }Step 2: Establish Dependency Collection System
// Store all dependency relationships const targetMap = new WeakMap() // WeakMap<target, Map<key, Set<effect>>> let activeEffect = null function track(target, key) { if (!activeEffect) return let depsMap = targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let deps = depsMap.get(key) if (!deps) { depsMap.set(key, (deps = new Set())) } deps.add(activeEffect) }Step 3: Implement Dependency Triggering
function trigger(target, key) { const depsMap = targetMap.get(target) if (!depsMap) return const deps = depsMap.get(key) if (deps) { deps.forEach(effect => effect()) } }Step 4: Create Effect Function
function effect(fn) { activeEffect = fn fn() // Execute the function, trigger getter, collect dependencies activeEffect = null } -
Complete Workflow Example
// Create reactive object const state = reactive({ count: 0 }) // Establish reactive effect effect(() => { console.log('count has changed:', state.count) }) // Modify data, automatically trigger effect state.count = 1 // Output: "count has changed: 1" -
Advanced Feature Implementation
Nested Effect Support:
const effectStack = [] function effect(fn) { const execute = () => { cleanup(effect) // Clear old dependencies activeEffect = effect effectStack.push(effect) fn() effectStack.pop() activeEffect = effectStack[effectStack.length - 1] } execute() }Scheduler Implementation:
function effect(fn, options = {}) { const effect = () => { // ...execution logic } effect.scheduler = options.scheduler // Support custom scheduling return effect }
Through this design, Vue3 can precisely track the dependency relationships of each property, efficiently trigger updates when data changes, and support more complex reactive scenarios such as nested effects, computed properties, etc.