1.shallowRef
ref() 的浅层作用形式。
和 ref()
不同,浅层 ref 的内部值将会原样存储和暴露,并且不会被深层递归地转为响应式。只有对 .value
的访问是响应式的。
shallowRef()
常常用于对大型数据结构的性能优化或是与外部的状态管理系统集成。
示例:
<template>
<div>
<div>{ {data.count}}</div>
<button @click="clickBtnNoChange">非响应</button>
<button @click="clickBtnChange">响应</button>
</div>
</template>
<script lang="ts" setup>
import { reactive, watch, getCurrentInstance, shallowRef } from 'vue'
const data = shallowRef({ count: 1 })
// 不会触发响应式-修改数据
const clickBtnNoChange = () => {
data.value.count++
}
// 会修改数据
const clickBtnChange = () => {
const random = Math.floor(Math.random() * 10 + 1)
data.value = { count: random }
}
</script>
2.triggerRef()
强制触发依赖于一个浅层 ref 的副作用,这通常在对浅引用的内部值进行深度变更后使用。
示例:
<template>
<div>
<div>{ {data.count}}</div>
<button @click="clickBtnNoChange">非响应</button>
<button @click="clickBtnChange">响应</button>
</div>
</template>
<script lang="ts" setup>
import { reactive, watch, getCurrentInstance, shallowRef, triggerRef } from 'vue'
const data = shallowRef({ count: 1 })
// 不会触发响应式-修改数据
const clickBtnNoChange = () => {
data.value.count++
// 执行修改-触发响应
triggerRef(data)
}
// 会修改数据
const clickBtnChange = () => {
const random = Math.floor(Math.random() * 10 + 1)
data.value = { count: random }
}
</script>
3.customRef()
创建一个自定义的 ref,显式声明对其依赖追踪和更新触发的控制方式。
customRef()
预期接收一个工厂函数作为参数,这个工厂函数接受 track
和 trigger
两个函数作为参数,并返回一个带有 get
和 set
方法的对象。
一般来说,track()
应该在 get()
方法中调用,而 trigger()
应该在 set()
中调用。然而事实上,你对何时调用、是否应该调用他们有完全的控制权。
示例:防抖
ts文件:
import { customRef } from 'vue'
export function useDebouncedRef(value:any, delay = 3000) {
let timeout:any;
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
Vue文件
<template>
<input v-model="text" />
</template>
<script lang="ts" setup>
import { useDebouncedRef } from './csgo.ts'
const text = useDebouncedRef('测试')
</script>
4.shallowReactive()
reactive() 的浅层作用形式
和 reactive()
不同,这里没有深层级的转换:一个浅层响应式对象里只有根级别的属性是响应式的。属性的值会被原样存储和暴露,这也意味着值为 ref 的属性不会被自动解包了。
谨慎使用
浅层数据结构应该只用于组件中的根级状态。请避免将其嵌套在深层次的响应式对象中,因为它创建的树具有不一致的响应行为,这可能很难理解和调试。
<template>
<div>
<div>{ {data.count}}</div>
<div>{ {data.add.add}}</div>
<button @click="clickBtnNoChange">非响应</button>
<button @click="clickBtnChange">响应</button>
</div>
</template>
<script lang="ts" setup>
import { reactive, watch, getCurrentInstance, shallowRef, triggerRef, shallowReactive } from 'vue'
const data = shallowReactive({
count: 1,
add: { add: 1 }
})
// 不会触发响应式
const clickBtnNoChange = () => {
data.add.add++
}
// 会修改数据-触发响应式
const clickBtnChange = () => {
const random = Math.floor(Math.random() * 10 + 1)
data.count = random
}
</script>
5.shallowReadonly()
和 readonly()
不同,这里没有深层级的转换:只有根层级的属性变为了只读。属性的值都会被原样存储和暴露,这也意味着值为 ref 的属性不会被自动解包了
谨慎使用
浅层数据结构应该只用于组件中的根级状态。请避免将其嵌套在深层次的响应式对象中,因为它创建的树具有不一致的响应行为,这可能很难理解和调试。
<template>
<div>
<div>{ {data.count}}</div>
<div>{ {data.add.add}}</div>
<button @click="clickBtnNoChange">按钮1</button>
<button @click="clickBtnChange">按钮2</button>
</div>
</template>
<script lang="ts" setup>
import { reactive, watch, getCurrentInstance, shallowRef, triggerRef, shallowReactive,shallowReadonly } from 'vue'
const data = shallowReadonly({
count: 1,
add: { add: 1 }
})
// 不会触发响应式
const clickBtnNoChange = () => {
// 可以更改下层嵌套对象
data.add.add++
}
// 不会触发响应式
const clickBtnChange = () => {
const random = Math.floor(Math.random() * 10 + 1)
// data中的count,无法调用。因为它是只读属性,但可以更改下层嵌套对象
// data.count = random
}
</script>
6.toRaw()
根据一个 Vue 创建的代理返回其原始对象。
toRaw()
可以返回由 reactive()、readonly()、shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象。
这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。不建议保存对原始对象的持久引用,请谨慎使用。
示例:
<template>
<div>
<div>{ {data.count}}</div>
<div>{ {data.add.add}}</div>
<button @click="clickBtnNoChange">按钮1</button>
<button @click="clickBtnChange">按钮2</button>
</div>
</template>
<script lang="ts" setup>
import { reactive, watch, getCurrentInstance, shallowRef, triggerRef, shallowReactive,shallowReadonly } from 'vue'
const data = shallowReadonly({
count: 1,
add: { add: 1 }
})
// 不会触发响应式
const clickBtnNoChange = () => {
// 可以更改下层嵌套对象
data.add.add++
}
// 不会触发响应式
const clickBtnChange = () => {
const random = Math.floor(Math.random() * 10 + 1)
// data中的count,无法调用。因为它是只读属性,但可以更改下层嵌套对象
// data.count = random
}
</script>