Ref全家桶包括:ref,shallowRef,triggerRef,customRef。其中:
- ref在包装引用类型变量时会调用reactive函数,但还是需要通过变量名.value.属性名来访问并修改才能达到响应式目的
- shallowRef即浅层响应式,其特点是响应式只能达到value层面,通过变量名.value = {}来改变,每次赋的值必须是一个新对象
- 不能在一个函数中同时修改ref和shallowRef的值,因为ref和shallowRef底层都是调用triggerRef强制更新收集的依赖并且强行更新DOM页面
- ref的底层是customRef,其作用是返回一个对象保存在变量中。当有人通过变量读取或修改这个对象时会拦截对应的操作并执行get或set方法
- ref函数的返回类型为Ref<类型>
<template>
<div>{{ Man }}</div>
<hr>
<div>{{ Man2 }}</div>
<button @click="change">修改</button>
<hr>
<div>{{ obj }}</div>
<button @click="changeCustom">修改custom</button>
</template>
<script setup lang="ts">
import { ref, reactive, shallowRef, Ref,customRef } from 'vue'
// 标记类型有两种方法:
interface M {
name: string
}
// const Man: Ref<M> = ref({ name: '小满' }) //第一种标记方式(推荐类型相对复杂时使用)
const Man = ref<{ name: string }>({ name: '小满' }) //第二种标记方式(简单的类型限制),不用引入Ref
/** 或者直接什么都不写,让TS编译器自行推断 */
const Man2 = shallowRef({ name: '小满' })
// 这一部分要借由变量挂载到模板上
function custom<T>(value:T){
return customRef((track,trigger)=>{
return {
get(){
console.log('检测到值被读取')
track()
return value
},
set(newValue){
console.log('检测到值被修改')
value = newValue
trigger()
}
}
})
}
let obj = custom<string>('小满')
// 注意这里也需要.value(customRef相当于Ref的底层逻辑)
const changeCustom = () => {
obj.value = '大满'
}
const change = () => {
/** 可以修改 */
Man.value.name = '大满'
console.log(Man.value.name)
/** 无法修改 */
Man2.value.name = '大满'
console.log(Man2.value)
// 原因:shallowRef只能检测到.value发生的变化
/** 可以修改 */
Man2.value = {
name: '大满',
}
/** 请注意:在一个函数中不能同时修改ref和shallowRef的值,否则会导致shallowRef的值也一起被修改(原因是底层都调用了triggerRef) */
}
/**
* 小结:
* Ref全家桶包括:ref,shallowRef,triggerRef,customRef。其中:
* 1.ref在包装引用类型变量时会调用reactive函数,但还是需要通过变量名.value.属性名来访问并修改才能达到响应式目的
* 2.shallowRef即浅层响应式,其特点是响应式只能达到value层面,通过变量名.value = {}来改变,每次赋的值必须是一个新对象
* 3.不能在一个函数中同时修改ref和shallowRef的值,因为ref和shallowRef底层都是调用triggerRef强制更新收集的依赖并且强行更新DOM页面
* 4.ref的底层是customRef,其作用是返回一个对象保存在变量中。当有人通过变量读取或修改这个对象时会拦截对应的操作并执行get或set方法
*/
</script>
<style scoped></style>