Vue响应式原理
💡Vue响应式原理详解|疑惑小记录
💡Proxy对象
Proxy 对象是 ECMAScript 6 引入的一种用于创建代理对象的特殊对象。它允许你在操作一个对象之前定义自定义的行为,这些行为会在对象的属性被读取、写入或删除时被触发。Proxy 对象提供了一种强大的机制,可以拦截并定义各种操作,例如属性查找、赋值、枚举等,从而实现元编程的功能。
Proxy 对象的基本语法如下:
1 |
|
target
:要包装的目标对象。handler
:一个包含了代理对象的拦截器(handler)方法的对象。
代理对象的拦截器方法包括了一系列钩子函数,比如 get
、set
、has
、deleteProperty
等,通过这些钩子函数,你可以定义在对目标对象进行操作时的行为。例如,你可以定义一个 get
钩子函数来拦截属性的读取操作,或者定义一个 set
钩子函数来拦截属性的赋值操作。
以下是一个简单的示例,展示了如何使用 Proxy 对象来拦截对象的读取和赋值操作:
1 |
|
在这个例子中,我们创建了一个代理对象 proxy
,它拦截了 target
对象的读取和赋值操作。当访问 proxy
对象的属性时,get
钩子函数会被触发,并输出一条日志;当对 proxy
对象的属性进行赋值时,set
钩子函数会被触发,并输出一条日志。
💡reactive()
和 ref()
reactive()
和 ref()
是 Vue 3 中用于创建响应式数据的两种不同方式。它们的主要区别在于它们处理数据的方式和用法:
reactive()
:reactive()
函数用于创建一个具有响应式特性的对象。- 当你使用
reactive()
包裹一个对象时,该对象的所有属性都会变成响应式的,即当对象的属性发生变化时,相关的视图会被重新渲染。 reactive()
返回的是一个 Proxy 对象,它会拦截对对象的所有操作,从而使得对对象的任何改变都能被 Vue 追踪到,并触发相应的更新。
1
2
3
4
5
6
7import { reactive } from 'vue';
const state = reactive({
count: 0
});
// state.count 会自动变为响应式的ref()
:ref()
函数用于创建一个具有响应式特性的简单数据值(比如数字、字符串等)。- 当你使用
ref()
包裹一个简单的数据值时,它会返回一个包含该值的响应式对象。但是,对于对象类型的数据,ref()
不会自动转换为响应式对象。 ref()
返回的是一个包含.value
属性的普通对象,当你需要获取数据时,需要通过.value
属性来访问。
1
2
3
4
5import { ref } from 'vue';
const count = ref(0);
// count.value 会自动变为响应式的
总结一下,主要区别在于:
reactive()
用于创建响应式对象,它处理复杂的对象类型数据,并且返回一个 Proxy 对象。ref()
用于创建响应式简单数据值,它处理基本的数据类型,返回一个带有.value
属性的普通对象。
值得注意的是,
reactive()
返回的是一个原始对象的Proxy,它和原始对象是不相等的:
1 |
|
只有代理对象是响应式的,更改原始对象不会触发更新。因此,使用 Vue 的响应式系统的最佳实践是 仅使用你声明对象的代理版本。
reactive()
函数用于创建一个具有响应式特性的对象。当你使用reactive()
包裹一个对象时,该对象的所有属性都会变成响应式的,但是该对象本身不会变成响应式的。因此,reactive()
函数返回的是一个 Proxy 对象,而不是一个响应式对象本身。
为保证访问代理的一致性,对同一个原始对象调用
reactive()
会总是返回同样的代理对象,而对一个已存在的代理对象调用reactive()
会返回其本身:
1 |
|
1 |
|
但是reactive()
API 有一些局限性:
- 有限的值类型
- 不能替换整个对象
- 对解构操作不友好
所以建议使用 ref()
作为声明响应式状态的主要 API
💡shallowRef()
- 浅层次响应
- 只到
x.value
,再深层的改变(比如x.value.name
)就不会响应了