ref 自动解包 - 不易发现的小秘密
在模板上下文中,只有顶级才能被解包
在下面代码,sex和info是顶级属性,但info.value.age却不是
--视图部分
{{ info.age + 1 }}
{{ '性别:' + sex }}
--js部分
const sex = ref('男')
const info = {
age: ref(18)
}
按照上面代码执行,第一行代码执行结果是[object object]1
,因为info.age
还是一个ref对象没有被解包。只有把它解构出来变成顶级属性,结果才能变成预期中的19
。
const {age} = info
还需要注意的一点是:如果ref是文本插值中的最终展示的值,它也可以被解构,这是文本插值中的一个便利的地方
{{info.age}}
浅层ref与常规ref的区别
1、浅层ref仅响应顶层属性变化换句话说就是只有把.value
整体换掉才会触发更新;常规ref则是整体换掉或修改其内部属性值都会触发更新。
// 创建浅层 ref
const state = shallowRef({
count: 0,
nested: { value: 1 }
})
// 会触发响应式更新(替换整个值)
state.value = { count: 10 }
// 不会触发更新(修改嵌套属性)
state.value.count = 20 // 无反应
state.value.nested.value++ // 无反应
2、浅层ref可以减少大型数据的响应性开销,从而达到优化性能的效果,但需要注意:改变其浅层ref变量的属性,不会让视图更新h; 如果遇到特殊情况可使用以下方式强制更新。
import { triggerRef } from 'vue'
// 修改内部属性后强制更新
state.value.nested.value = 30
triggerRef(state) // 手动触发更新
为什么使用.value的ref
首先我们需要简单了解一下vue的响应式系统
它是怎么样的工作的。
当使用一个ref变量,且在过程中对变量进行了访问和修改,vue会监听变量的变化,然后让对应的DOM
进行响应更新。
在标准JavaScript中,监听普通变量访问和修改是行不通的,但可通过getter和setter方法来拦截对象get、set的操作,而.value
给了vue检测的机会
// 伪代码,不是真正的实现
const myRef = {
_value: 0,
get value() {
track()
return this._value
},
set value(newValue) {
this._value = newValue
trigger()
}
}
ref与reactive的pk - 谁会更胜一筹
我们会从reactive()
的局限性作为一个切入点,进行讨论。
1、reactive只能使对象类型
的数据具有响应式,但ref可以让对象类型
(如:对象、数组等)和原始类型
(如:string、number等)的数据都具有响应式。
2、reactive
不能替换整体对象,因为vue的响应式是追踪属性实现的;但ref
是通过.value
调用的,所以可以替换整个对象。
3、reactive
对解构不友好,当我们将响应式对象解构为一个变量或者将该属性值传给函数,就会丢失响应式链接
const state = reactive({ count: 0 })
// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++
// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count)
基于以上几点,建议使用ref
作为声明响应式变量的主要API
彩蛋
我在寻找志同道合的同学,互相监督坚持每日打卡学习,学习路线如下:css、vue、JavaScript、node、如何使用AI来提升编程能力,如果你有兴趣可以私信我或直接联系我 wx:wx_zysu