Skip to content

vue3 响应式

仲灏约 1 分钟

vue3 响应式

回顾 Object.defineProperty

基本用法

js
// Object.defineProperty 的基本用法
const data = {}
const name = 'zhangsan'
Object.defineProperty(data, "name", {
    get: function () {
        console.log('get')
        return name  
    },
    set: function (newVal) {
        console.log('set')
        name = newVal
    }
});

// 测试
console.log(data.name)  // 可以监听到
data.name = 'lisi'      // 可以监听到

监听数据变化,参考 code-1.js

总结 Object.defineProperty 缺点:

  • 深度监听,需要递归到底
  • 无法监听新增属性/删除属性(Vue.set Vue.delete)
  • 无法监听数组,需要特殊处理

使用 Proxy

我们已知:

  • Proxy 可以原生监听 新增/删除属性
  • Proxy 原生支持监听数组变化

接下来看看 Proxy 如何实现深度监听。参考 code-2.js

两者对比

  • 深度监听,都用递归。但前者是一次性递归,后者是访问时再递归。
  • Proxy 原生能监听 新增/删除属性
  • Proxy 原生支持监听数组变化

但 —— Proxy 兼容性不好 ,我见过,oppo vivo 的某些机型,某些 app 的 webview 还没有支持 ES6 。

vue3 响应式实现

响应式的作用:监听 data 数据变化,仅此而已。所以,不要掺杂进其他功能进来。

回顾

  • 回顾 Object.defineProperty 方式
  • 回归 Proxy 语法
  • 回顾 Map 和 Set 语法

Proxy 实现

用 Proxy 模仿 Vue 3.0 的响应式

学习用法

  • 下载 vue-next ,然后查看测试用例,看 packages/reactivity/__tests__/effect.spec.ts
  • basic properties ,找到使用方式

源码编写,步骤如下

  • reactivity-1.js 实现简单的 Proxy 监听
  • reactivity-2.js 深度监听,修改 get 的代码
  • reactivity-3.js 监听数组,修改 get 去掉原型方法,修改 set 区分新增属性和修改属性,不重复修改属性
  • reactivity-4.js 避免重复代理
    • 新建 toProxyMaptoRawMap
    • createReactiveObject
      • 创建 proxy 之前,判断 toProxyMap 是否有对应的 proxy
      • 创建 Proxy 之前,判断 toRawMap 是否已有对应的 proxy
      • 生成 proxy 之后,设置 toProxyMap
      • 生成 proxy 之后,设置 toRawMap
  • reactivity-5.js 接收副作用,先初始化时能执行一次。创建 effect createReactiveEffect runactiveEffectStacks
  • reactivity-6.js 响应式副作用
    • 新建 targetsMap
    • 新建 track 函数,并在 get 时执行
    • 新建 trigger 函数,并在 set 时执行

总结 Proxy 比 Object.defineProperty 的优点?

  • 深度监听时,Proxy 延迟递归,而不是一上来就全部递归,性能好
  • 原生支持监听数组
  • 原生支持新增和删除属性

上次更新:

讨论区

欢迎留下想法与补充