2024.05.11

vue 响应式(2)

数据响应式

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

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

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

这就涉及到数据拦截了

在 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

reactive

响应式处理的关键

  • ref 的处理逻辑
    • 根据传入值的类型决定使用 getter/setter 还是 Proxy
    • 基本类型使用 getter/setter
    • 引用类型使用 Proxy
  • 依赖收集机制
    • 对象操作只有被拦截的才会触发依赖收集

Vue3 中的响应式数据

  • ref
  • reactive
  • props
  • computed

响应式的核心机制:

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

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

函数

  • effect
  • watch
  • watchEffect
  • h
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)