Vue 3 响应式系统简明指南

138 阅读2分钟

🌟 核心概念

响应式数据:当数据变化时,依赖它的代码自动重新执行
副作用 (Effect) :需要响应数据变化的操作(如:视图渲染、计算属性)


🛠️ 核心机制

1. 依赖收集与触发

javascript
复制代码
// 三级存储结构
const targetMap = new WeakMap()  // 对象级存储Map()          // 属性级存储Set()       // 副作用集合

2. 工作流程

mermaid
    A[响应式对象] -->|被读取| B[track 收集依赖]
    A -->|被修改| C[trigger 触发更新]
    D[effect 函数] -->|执行时| E[标记 activeEffect]
    B --> E
    C -->|通知| D

🔑 核心 API 实现

1. reactive() - 对象响应化

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      track(target, key)         // 收集依赖
      return Reflect.get(...arguments)
    },
    set(target, key, value) {
      const res = Reflect.set(...arguments)
      trigger(target, key)       // 触发更新
      return res
    }
  })
}

特点
✅ 深度响应嵌套对象
🚫 只能处理对象/数组类型
💡 适用于复杂数据结构


2. ref() - 通用响应容器

function ref(value) {
  return {
    _value: value,
    get value() {
      track(this, 'value')       // 收集依赖
      return this._value
    },
    set value(newVal) {
      this._value = newVal
      trigger(this, 'value')     // 触发更新
    }
  }
}

特点
✅ 可包装任意类型值
🔍 通过 .value 访问
💡 适合原始值或需要替换整个对象时使用


3. effect() - 副作用管理


function effect(fn) {
  const _effect = () => {
    activeEffect = _effect       // 标记当前副作用
    try { fn() } finally { activeEffect = null }
  }
  _effect()                      // 立即执行以收集依赖
  return _effect
}

典型场景

  • 组件渲染
  • 计算属性
  • 监听器

🎯 关键设计解析

1. 依赖追踪原理

// 当访问响应式数据时
function track(target, key) {
  if (!activeEffect) return
  
  // 建立三级存储关系
  let depsMap = targetMap.get(target) || targetMap.set(target, new Map()).get(target)
  let dep = depsMap.get(key) || depsMap.set(key, new Set()).get(key)
  dep.add(activeEffect)
}

2. 更新触发机制

// 当修改响应式数据时
function trigger(target, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  
  // 执行所有关联的副作用
  depsMap.get(key)?.forEach(effect => effect())
}

💡 最佳实践

  1. 原始值用 ref

    javascript
    复制代码
    const count = ref(0)
    
  2. 对象用 reactive

    const user = reactive({ name: 'Alice' })
    
  3. 组合使用

      profile: reactive({ 
        age: 25 
      })
    })
    
  4. 避免陷阱

    // ❌ 错误:直接解构会失去响应性
    const { count } = reactive({ count: 0 })
    
    // ✅ 正确:使用 toRefs
    const { count } = toRefs(reactiveObj)
    

🚀 性能优化

  1. 减少大对象响应化
  2. 合理使用 shallowRef/shallowReactive
  3. 及时清理无用 effect