Vue3 使用 Proxy 来监听数据的变化
响应性是 VueJS 的核心,数据必须具有依赖性,可以观察并进行更新以响应任何更改,Vue2 使用 Object.defineProperty 创建 getter
和 setter
来实现响应式。
使用Object.defineProperty
有两个主要问题,在官方文档中都提到过:Vue 不能检测数组和对象的变化。
对于对象
Vue 无法检测 property
的添加或移除。由于 Vue 会在初始化实例时对 property
执行 getter/setter
转化,所以 property
必须在 data
对象上存在才能让 Vue 将它转换为响应式的。
对于数组
Vue 不能检测以下数组的变动:
- 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:vm.items.length = newLength
举个例子:
var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // 不是响应性的 vm.items.length = 2 // 不是响应性的
为什么使用 Proxy ?
Vue3 的解决方案是使用基于Proxy
的观察者模式来解决 Vue2 响应上的一些限制。
新旧系统之间的主要区别在于,在Vue2中,Object.defineProperty
会修改原始数据,而Proxy
则不会,Proxy
虚拟化目标数据并设置不同的处理程序(称为target
),这些处理程序通过getters
和setter
拦截数据。
Vue3 意味着我们无需使用vm.$set
来让数据动态的响应,同时也解决 vue2 操作数组无法响应的问题。
正如尤雨溪大哥所总结的那样,基于代理可以支持:
- 检测属性
添加/删除
- 检测数组
index/length
的变化 - 支持
Map
,Set
,WeakMap
和WeakSet
Composition API
这是到目前为止 Vue3 最大的一个变化,它有助于代码的组织和重用性。
目前,在Vue中我们使用是Options API
。Options API
按属性组织代码:data
,computed
,methods
等。
这是一个非常直观的方式,但维护一些复杂组件变得非常困难。单个功能的代码通常在相隔数百行的多个地方抛出。
可维护性和可读性成为主要问题。
接着,我们快速了解一下Composition API的工作原理。
import { reactive, computed } from 'vue' export default { setup() { let state = reactive({ input: '', groceries: [], groceriesLeft: computed(() => { groceries.length }) }) function addGrocery() { state.groceries.push(state.input) state.input = '' } function deleteGrocery(index) { state.groceries.splice(index, 1); } return { state, addGrocery, deleteGrocery } } }
我们来分析一下,上面的过程