Principles of Vue3 Reactive System

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

  1. 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).
  2. 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.
  3. 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
    }
    
  4. 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"
    
  5. 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.