【Vue3 入门到实战】13. 常用 API
目录
1. shallowRef 与 shallowReactive
1.1 shallowRef演示
1.2 shallowReactive演示
1.3 小结
2. readonly 与 shallowReadonly
2.1 readonly
编辑
2.2 shallowReadonly
3. toRaw 与 markRaw
3.1 toRaw
3.2 markRaw
4. customRef 自定义ref
5. 总结
1. shallowRef 与 shallowReactive
1.1 shallowRef演示
shallowRef:ref 的浅层作用形式。只会对顶层的值进行响应式转换,而不会深入嵌套的对象或数组内部进行响应式处理。
效果演示 ↓ ↓ ↓
当我们使用 ref 定义时
代码如下
<template>
<div>
<h3>姓名:{{ obj.name }}</h3>
<h3>年龄:{{ obj.age }}</h3>
<h3>地址:{{ obj.address.city }}</h3>
<button @click="changename">修改姓名</button>
<button @click="changeage">修改年龄</button>
<button @click="changeaddress">修改地址</button>
<button @click="changeobj">修改整体</button>
</div>
</template>
<script setup>
import { ref, reactive, shallowRef, shallowReactive } from 'vue'
let obj = ref({
name: 'zhangsan', age: 18,
address: {
city: '北京',
}
})
function changename() {
obj.value.name = 'lisi'
}
function changeage() {
obj.value.age = 19
}
function changeaddress() {
obj.value.address.city = '上海'
}
function changeobj() {
obj.value = {
name: 'wangwu', age: 20, address: {
city: '深圳',
}
}
}
</script>
顶层和嵌套的内部数据都是响应式的。
当我将 ref 换成 shallowRef 定义时
只有顶层才是响应式。
1.2 shallowReactive演示
shallowReactive:reactive 的浅层作用形式。只会对对象的第一层属性进行响应式转换,而不会递归地将嵌套对象转换为响应式对象。
演示效果 ↓ ↓ ↓
当我们使用 reactive 定义时
代码如下
<template>
<div>
<h3>姓名:{{ obj.name }}</h3>
<h3>年龄:{{ obj.age }}</h3>
<h3>地址:{{ obj.address.city }}</h3>
<button @click="changename">修改姓名</button>
<button @click="changeage">修改年龄</button>
<button @click="changeaddress">修改地址</button>
<button @click="changeobj">修改整体</button>
</div>
</template>
<script setup>
import { ref, reactive, shallowRef, shallowReactive } from 'vue'
let obj = reactive({
name: 'zhangsan', age: 18,
address: {
city: '北京',
}
})
function changename() {
obj.name = 'lisi'
}
function changeage() {
obj.age = 19
}
function changeaddress() {
obj.address.city = '上海'
}
function changeobj() {
Object.assign(obj,{
name: 'wangwu',
age: 20,
address: {
city: '深圳'
}
})
}
</script>
注意:reactive 无法直接修改整体,可以通过 Object.assign() 来修改。
可以看到顶层和嵌套的都具有响应式。
当我将 reactive 换成 shallowReactive 时。
只有对对象的顶层和第一层进行响应式转换,而不会递归地将嵌套对象转换为响应式对象。
1.3 小结
通过使用 shallowRef 和 shallowReactive 来绕开深度响应。浅层式API创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理,避免了对每一个对象内部属性做响应式所带来的性能成本,这使得属性的访问变得更快,可提升性能。
2. readonly 与 shallowReadonly
2.1 readonly
用于创建一个对象的深只读副本。包括所有嵌套对象都是只读。
特点:
(1) 对象的所有嵌套属性都将变为只读。
(2) 任何尝试修改这个对象的操作都会被阻止(在开发模式下,还会在控制台中发出警告)。
演示效果 ↓ ↓ ↓
代码如下
<template>
<div>
<h2> sum求和为:{{ sum }}</h2>
<h2> sum2求和为:{{ sum2 }}</h2>
<button @click="sum++">sum加</button>
<button @click="sum2++">sum2加</button>
</div>
</template>
<script setup>
import { ref, readonly, shallowReadonly } from 'vue'
let sum = ref(1);
let sum2 = readonly(sum);
</script>
当我修改sum2时,控制台会弹出提示,无法修改。
2.2 shallowReadonly
与 readonly 类似,但只作用于对象的顶层属性。确保顶层属性不被修改,允许嵌套对象内部变化。
代码如下
<template>
<div>
<h2> sum名字:{{ sum.name }}</h2>
<h2> sum年龄:{{ sum.age }}</h2>
<h2> sum地址:{{ sum.address.city }}</h2>
<h2> sum2为:{{ sum2 }}</h2>
<button @click="changename">sum2修改name</button>
<button @click="changeage">sum2修改age</button>
<button @click="changeaddress">sum2修改address</button>
<button @click="changeall">sum2修改整个</button>
</div>
</template>
<script setup>
import { ref, reactive, readonly, shallowReadonly } from 'vue'
let sum = ref({
name: 'hhh',
age:20,
address:{
city:'北京'
}
});
let sum2 = shallowReadonly(sum);
function changename(){
sum2.value.name = 'hhh2';
}
function changeage(){
sum2.value.age = 21;
}
function changeaddress(){
sum2.value.address.city = '上海';
}
function changeall(){
sum2.value = {
name: 'hh',
age:2,
address:{
city:'京'
}
}
}
</script>
下图可以看到,除了最顶层(这里是整个sum2)设置为只读外,其他都没有设置只读。
注意: 如果将 ref 变为 reactive,那么第一层是只读,不会影响其他嵌套层。
3. toRaw 与 markRaw
3.1 toRaw
用于获取一个响应式对象的原始对象, toRaw 返回的对象不再是响应式的,不会触发视图更新。
适用场景:在需要将响应式对象传递给非 `Vue` 的库或外部系统时,使用 toRaw 可以确保它们收到的是普通对象。
代码如下
<template>
<div>
<div>{{sum2.name}}</div>
<button @click="changename">修改sum2的name</button>
</div>
</template>
<script setup>
import { ref, reactive, toRaw } from 'vue'
let sum = reactive({
name: 'hhh',
age:20,
address:{
city:'北京'
}
});
let sum2 = toRaw(sum)
function changename(){
sum2.name = 'hhh2'
console.log(sum,sum2)
}
</script>
如下图所示,用 sum2 接收 toRaw 包裹的响应式对象,结果 sum2 失去了响应式 。
3.2 markRaw
标记一个对象,使其永远不会变成响应式的。
代码如下
<template>
<div>
<div>{{ sum2.name }}</div>
<button @click="changename">修改sum2的name</button>
</div>
</template>
<script setup>
import { reactive,markRaw } from 'vue'
let sum = markRaw({
name: 'hhh',
age: 20,
address: {
city: '北京'
}
})
let sum2 = reactive(sum)
console.log(sum,sum2)
</script>
如下入所示,当 sum 对象被 markRaw 标记之后,就算被 reactive 包裹,也不会转成响应式对象。
4. customRef 自定义ref
创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行逻辑控制。
下面我们使用自定义 ref 来实现一个防抖效果,用来熟悉这个 customRef。
代码如下
<template>
<div>
<h2>{{ msg }}</h2>
<input type="text" v-model="msg">
</div>
</template>
<script setup>
import { customRef } from 'vue'
let initValue = '你好'
let time
let msg = customRef((track,trigger)=>{
return {
// 当msg被读取时调用
get(){
track() // 告诉Vue,这个msg数据很重要,你要对msg进行持续关注,一旦msg变化就去更新
console.log('hhh,我被读取啦')
return initValue
},
// 当msg被修改时调用
set(value){
clearTimeout(time)
time = setTimeout(()=>{
console.log('hhh,我被修改啦',value)
initValue = value
trigger() // 告诉Vue,这个msg数据发生了变化,去更新
},1000)
}
}
})
</script>
效果如下 ↓ ↓ ↓
注意点:
(1) get 方法在数据读取时被调用。
(2) set 方法在数据修改时被调用。
(3) track 方法用于 告诉这个Vue,该数据很重要,要对这个数据进行持续关注。
(4) trigger 方法用于 告诉Vue,这个数据发生了变化,去更新。
为了提高代码的复用性,可以将这个自定义ref,封装成一个 hooks,每次使用直接引用既可。
创建一个hooks并暴露
useCustomRef.ts
import { customRef } from "vue";
export default function useCustomRef(value:string,delay:number){
return customRef((track,trigger)=>{
let timer:any = null
return {
get(){
track();
return value
},
set(newValue:string){
clearTimeout(timer)
timer = setTimeout(()=>{
value = newValue
trigger()
},delay)
}
}
})
}
在组件中直接引用
App.vue
<template>
<div>
<h2>{{ msg }}</h2>
<input type="text" v-model="msg">
</div>
</template>
<script setup>
import useCustomRef from "@/useCustomRef"
let msg = useCustomRef('hello',1000)
</script>
效果和上面是一样的。
5. 总结
上面主要介绍了Vue3常用的一些API,包括浅层API(shallowRef)、只读API(readonly)、toRaw、markRaw、自定义ref(customRef)等。
更多内容点击下方链接 ↓ ↓ ↓
Vue3入门到实战_借来一夜星光的博客-CSDN博客