Skip to content

数据响应式

  • 自动追踪数据与视图的依赖关系
  • 在数据发生变化时智能更新相关联的视图

那是如何追踪数据依赖关系的?

在数据改变的时候,是如何更新视图的?

这就涉及到数据拦截了

在 vue2 中是使用的 Object.defineProperty

在 vue3 中是使用的 proxy(也不太对,defineProperty 也有用到)

Object.defineProperty

Proxy

两者的区别

共同点

  • 都可以拦截 操作
  • 都可以实现深度拦截,需要递归处理

不同点

  1. 拦截的目标和行为是不同的
    1. Object.defineProperty 是针对对象的特定属性进行读写操作的拦截
    2. Proxy 针对对象的多种操作,包括属性读、写、删除、函数调用、原型设置等。
      1. 比如删除对象上的一个属性
      2. 给对象上增加一个不存在的属性
  2. 性能上的区别
    1. 如果需要拦截的对象属性很多,使用 Proxy 性能更好,可以一次性对整个对象处理
    2. 如果需要拦截的对象很少,使用 Object.defineProperty 会好点

Vue 中的响应式系统源码

RefImpl

RefImpl 源码实现

reactive

reactive 函数源码

createReactiveObject 源码

响应式处理的关键

  • ref 的处理逻辑

    • 根据传入值的类型决定使用 getter/setter 还是 Proxy
    • 基本类型使用 getter/setter
    • 引用类型使用 Proxy
  • 依赖收集机制

    • 对象操作只有被拦截的才会触发依赖收集

Vue3 中的响应式数据

  • ref
  • reactive
  • props
  • computed

响应式的核心机制:

  1. 当响应式数据发生变化时,会自动触发相关联的函数重新执行
  2. 依赖关系的建立需要满足:
    • 函数必须在执行过程中访问响应式数据
    • 响应式数据的访问必须被系统拦截和追踪
    • 函数必须是被监控的函数
    • 同步代码

一句话描述就是 只有被监控的函数,在同步代码运行期间,读取操作被拦截的响应式数据,才会建立依赖关系建立依赖关系后,响应式数据发生变化,对应的函数才会重新执行

函数

  • effect
  • watch
  • watchEffect
  • h
js
import { ref, watchEffect } from 'vue'

const state = ref({
  a: 1
})

const k = state.value

const n = k.a

watchEffect(() => {
  console.log('start')
  state.value.a
})

setTimeout(() => {
  state.value = { a: 1 }
}, 500)

setTimeout(() => {
  k.a = 11
}, 1000)

最后更新时间: