和
ref()
不同,浅层 ref 的内部值将会原样存储和暴露,并且不会被深层递归地转为响应式。只有对.value
的访问是响应式的。
shallowRef()
常常用于对大型数据结构的性能优化或是与外部的状态管理系统集成。
shallowRef():只有第一层数据变了组件才会重新渲染,深层数据变了组件不会重新渲染,watch也监听不到变化。
简而言之就是第一层是响应式数据,非第一层数据不是响应式数据
上面的shallowRef()的作用是只有第一层数据变了才会重新渲染,那如果某种情况需要改变深层的某个数据怎么办?这时候就可以用triggerRef()
改变深层数据时强制渲染组件。
shallowRef()和triggerRef()是一对死对头,前者是深层数据改变的时候不让重新渲染组件,后者则是深层数据改变的时候偏偏就要重新渲染组件。
<script setup>
import { shallowRef, triggerRef } from 'vue'
const state = shallowRef({ count: 1 })
// shallowRef: 只有第一层数据变了组件才会重新渲染,深层数据变了组件不会重新渲染
// 按钮触发事件
function change() {
// 数据会变,组件不会重新渲染,页面上显示的还是1
state.value.count = 2
// 数据会变,组件会重新渲染,页面上显示的会变成2
// state.value = { count: 2 }
// 强制更新state 组件会重新渲染,页面上显示会变成2
triggerRef(state)
}
</script>
<template>
<div>
{{ state.count }}
<button @click='change'>改变</button>
</div>
</template>
customRef():创建一个可以自己指定get和set方法的ref数据
customRef() 传入一个工厂函数,工厂函数中会有track和trigger两个参数,这两个参数都是函数。track是在get方法中触发,trigger是在set方法中触发。
track和trigger两个函数的作用就是将数据变成响应式,触发其他的方法,比如只有触发了track和trigger两个函数组件才会重新渲染,页面数据才会变。不然别的地方是不知道什么时候获取了数据,什么时候改变了数据。
<script setup>
import { customRef } from 'vue'
let value = "高启强"
// customRef()中传入一个工厂函数,这个工厂函数接受 track 和 trigger 两个函数作为参数
const myRef = customRef((track, trigger) => {
// 返回一个带有 get 和 set 方法的对象
return {
get() {
console.log('获取数据');
track()
return value
},
set(newValue) {
console.log('改变数据');
value = newValue
trigger()
}
}
})
function change() {
console.log(myRef.value);
// 获取数据
// 高启强
myRef.value = '高启兰'
console.log(myRef.value);
// 改变数据
// 获取数据
// 高启兰
}
</script>
<template>
<div>
{{ myRef }}
<button @click='change'>修改</button>
</div>
</template>
和shallowRef()方法作用一样,shallowReactive()也是监听第一层数据,不一样的是数据是reactive数据,不是ref数据。shallowReadonly()是readonly数据,和前两数据刚好相反,只有第一层是不可修改的。
toRaw()方法的作用就是将数据打回原形,把身上的其他Vue监听方法都去掉,恢复到最原始的js数据。
toRaw()
可以返回由reactive()
、readonly()
、shallowReactive()
或者shallowReadonly()
创建的代理对应的原始对象
<script setup>
import { toRaw, reactive } from 'vue'
// 原始数据
const obj = {
name: '孙悟空'
}
// reactive数据
const obj1 = reactive(obj)
console.log(obj1 === obj); // false
// 使用toRaw获取到原始数据
const obj2 = toRaw(obj1)
console.log(obj2 === obj); // true
</script>
<script setup>
import { markRaw, reactive, isReactive } from 'vue'
// 原始数据
const obj = {
name: '孙悟空'
}
// 将原始数据保护起来,不能转为其他数据
const markObj = markRaw(obj)
// 将保护起来的数据转为reactive数据(这里不会转成功,因为已经被markRaw保护过了)
const obj1 = reactive(markObj)
// 不是reactive数据
console.log(isReactive(obj1)); // false
// 和原始数据一样
console.log(obj1 === obj); // true
</script>