文章目录
响应式系统API
reactive
const obj = reactive({ count: 0 })
相当于Vue 2.x中的Vue.observable()
API,返回一个普通对象的响应式代理,响应式转换是深层的,会影响对象内部嵌套的属性,基于ES2015的Proxy实现,返回的代理对象不等于原始对象,要避免使用原始对象
经过试验,Vue3中可以通过修改数组下标来响应式的更改数组成员的值了
reactive
将自动解构所有深层次的refs
,同时维持ref
的响应性
const count = ref(1)
const obj = reactive({ count })
// ref 会被解构
console.log(obj.count === count.value) // true
// 它会更新 `obj.value`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2
ref
ref
的引入是为了以变量形式传递响应式的值而不再依赖访问this
:
const count = ref(0)
接受一个参数,返回一个响应式可改变的ref
对象,ref
对象拥有一个指向内部值的单一属性.value
ref
主要目的是保证基本类型值的响应式,如果传入的参数不是基本类型,会调用reative
方法进行深层响应式转换
ref
使用时:
ref
的返回值setup
中返回应用在模板中时,会自动解构,不需要书写.value
ref
作为reactive
对象的属性被修改或访问时,也会自动解构,不需要书写.value
- 通过
Array
、Map
等原声集合类中范围ref
时,不会自动解构,需要使用.value
获取值
reactive
VS ref
使用ref
和reactive
的区别可以通过如何撰写编撰的JavaScript逻辑比较
// 风格 1: 将变量分离
let x = 0
let y = 0
function updatePosition(e) {
x = e.pageX
y = e.pageY
}
// --- 与下面的相比较 ---
// 风格 2: 单个对象
const pos = {
x: 0,
y: 0,
}
function updatePosition(e) {
pos.x = e.pageX
pos.y = e.pageY
}
使用ref
就是将将风格(1)转换为使用ref
,让基础类型值也具有响应性,使用reactive
和风格(2)一致
只使用reactive
的问题是,使用组合函数的时候必须始终保持对这个组合函数返回对象的引用以保持响应性,这个对象不能够被解构或者展开
// 组合函数:
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0,
})
// ...
return pos
}
// 消费者组件
export default {
setup() {
// 这里会丢失响应性!
const { x, y } = useMousePosition()
return {
x,
y,
}
// 这里会丢失响应性!
return {
...useMousePosition(),
}
// 这是保持响应性的唯一办法!
// 你必须返回 `pos` 本身,并按 `pos.x` 和 `pos.y` 的方式在模板中引用 x 和 y。
return {
pos: useMousePosition(),
}
},
}
解决方法是使用toRefs
将响应式对象的每个对象都转换为响应的ref
:
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0,
})
// ...
return toRefs(pos)
}
// x & y 现在是 ref 形式了!
const { x, y } = useMousePosition()
目前阶段可以从下面两种风格二选其一:
(1)如果在普通的JavaScript中声明基础变量类型与对象变量时一样区别使用ref
和reacitve
,也就是说如果声明响应式的基础类型使用ref
,如果声明响应式对象变量使用reactive
(2)全部使用reactive
,然后在组合函数返回对象时使用toRefs
目前(2020.08.01)官方对ref
和reactive
的最佳实践还没有建议,自己选择更适合自己的风格使用,我会选择风格1使用。
readonly
如果我们希望一个响应式对象在某些情况下被改变,例如我们提供了一个Provide的响应式对象,不希望它在被注入时被改变,这时就可以基于原始对象创建一个只读的Proxy对象