阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > reactive与ref的实现机制

reactive与ref的实现机制

作者:陈川 阅读数:28033人阅读 分类: Vue.js

在Vue3的响应式系统中,reactiveref是核心API,它们分别针对对象和基本类型数据实现响应式。两者底层均依赖Proxy和依赖收集机制,但在使用场景和内部实现上存在显著差异。

reactive的实现机制

reactive通过Proxy代理目标对象,拦截属性的读取(get)和设置(set)操作。当访问属性时,触发track函数收集依赖;当修改属性时,触发trigger函数通知更新。以下是简化实现:

function reactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      track(target, key) // 依赖收集
      return Reflect.get(target, key, receiver)
    },
    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
    }
  })
}

深层响应式通过递归实现:

function reactive(target) {
  if (isObject(target)) {
    Object.entries(target).forEach(([key, val]) => {
      if (isObject(val)) target[key] = reactive(val)
    })
  }
  return /* Proxy逻辑 */
}

对于数组的特殊处理体现在拦截push等方法:

const arrayInstrumentations = {
  push(...args) {
    const res = Array.prototype.push.apply(this, args)
    trigger(this, 'length') // 手动触发length变更
    return res
  }
}

ref的实现机制

ref通过对象包装基本类型值,利用value属性访问实际值。其核心实现如下:

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

对象类型处理存在优化:

function ref(value) {
  return isObject(value) 
    ? reactive(value) // 直接转为reactive
    : createRef(value)
}

模板中自动解包特性通过编译阶段实现:

<script setup>
const count = ref(0)
</script>

<template>
  <!-- 编译为count.value -->
  <button @click="count++">{{ count }}</button>
</template>

两者差异对比

性能方面,ref在基本类型场景更高效:

// 创建10000个响应式变量
const refs = Array(10000).fill(0).map(() => ref(0)) // 更快
const reactives = Array(10000).fill(0).map(() => reactive({ value: 0 }))

类型系统支持差异明显:

const numRef = ref<number>(0) // 明确类型
const objReactive = reactive<{ foo: string }>({ foo: 'bar' }) // 自动推断

解构行为对比:

const state = reactive({ x: 1, y: 2 })
const { x } = state // 失去响应性
const xRef = toRef(state, 'x') // 保持响应性

底层依赖追踪系统

track函数建立依赖关系:

const targetMap = new WeakMap()
function track(target, key) {
  if (!activeEffect) return
  let depsMap = targetMap.get(target)
  if (!depsMap) targetMap.set(target, (depsMap = new Map()))
  let dep = depsMap.get(key)
  if (!dep) depsMap.set(key, (dep = new Set()))
  dep.add(activeEffect)
}

trigger函数触发更新:

function trigger(target, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)
  effects && effects.forEach(effect => effect())
}

特殊场景处理

readonly实现共享部分逻辑:

function readonly(target) {
  return new Proxy(target, {
    get: createGetter(true),
    set(target, key) {
      console.warn(`Set operation on key "${key}" failed: target is readonly.`)
      return true
    }
  })
}

shallowReactive的浅层响应:

function shallowReactive(target) {
  return new Proxy(target, {
    get(target, key) {
      track(target, key)
      const res = Reflect.get(target, key)
      return isObject(res) ? res : reactive(res) // 不递归处理
    }
  })
}

响应式API的演进

Vue3.3引入的reactivity transform

// 编译前
let count = $ref(0)
function increment() {
  count++
}

// 编译后
let count = ref(0)
function increment() {
  count.value++
}

与Composition API的配合:

function useCounter() {
  const count = ref(0)
  const double = computed(() => count.value * 2)
  return { count, double }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌