我是靠谱客的博主 虚拟棒球,这篇文章主要介绍vue3响应式之ref、reactive、toRef、toRefs、toRawrefref与reactive如何选择ref 与reactive使用reactivetoReftoRefsref和toRef的区别toRef 、toRefs、toRaw,现在分享给大家,希望可以做个参考。

ref

ref取值或赋值时需要加.value

复制代码
1
2
3
let form = ref({age:18}) // 修改值 form.value.age = 28

ref 深层响应对象

一般使用在简单的数据类型,如:string , numberBooleanSymbol单值对象【即:只有一个属性值的对象】(如:{ count: 1 })

复制代码
1
import { ref , isRef , shallowRef , triggerRef , customRef } from 'vue'

方案一:接收泛型

复制代码
1
2
type U = { name:string } const user = ref<U>({name:"Fish"})    // ref<U>( )

方案二:如果类型复杂,则使用Ref,使用Ref来自定义

复制代码
1
2
3
import type { Ref } from 'vue' type U = { name:string } const user:Ref<U> = ref({name:"Fish"})    // :Ref<U>

方案三:或者什么都不写,自动推断

复制代码
1
const user = ref({name:"Fish"}) // 使用ref()进行包裹, 自动推断

修改值时,返回的是ES6的一个,有个属性.value,修改或取值(CURD)必须加.value,修改后放在value中的Proxy中。

isRef 判断是否是ref对象

返回boolean

复制代码
1
isRef( user )    // 返回 true

shallowRef 浅层响应

shallowRef是浅层次响应,在user.value.name中,只到.value赋值,不能到.name

复制代码
1
2
3
4
5
6
const user = shallowRef({ name:"Fish" }) const change = () => { user.value.name = 'Fisher' console.log(user)                    // 值已改变   // <div>shallowRef:{{ user }}</div> // 视图不改变 }
复制代码
1
2
3
4
5
6
const user = shallowRef({ name:"Fish" }) const change = () => { user.value = {name:'Fisher'} console.log(user)                 // 值已改变 // <div>shallowRef:{{ user }}</div> // 视图也改变 }

注意:ref , shallowRef不能同时使用

否则,shallowRef会受到ref的影响,造成shallowRef视图的更新。

因为在ref底层更新逻辑时,会调用triggerRef函数。

triggerRef 强制更新收集的依赖

复制代码
1
2
3
4
5
6
const user = shallowRef({name:Fish}) const change = () => { user.value.name = 'Fisher' triggerRef(user) console.log(user) // 视图将改变 }

customRef 自定义一个ref

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function MyRef<T>( value:T ){     return customRef((track,trigger)=>{         return {             get(){                 track()    // 收集依赖                 return value             }             set( newValue ){                 console.log('触发------')                 value = newValue                 trigger()    // 触发依赖 }         }     }) }

使用方法

复制代码
1
2
3
4
5
6
    // 1.script const obj = MyRef<string>('Fish')     // 2.视图中 {{ obj }}     // 3.改值也需要加.value [script] obj.value = '修改啦'

作用:触发时,调用接口

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 简单防抖 function MyRef<T>( value:T ){     let timer:any return customRef((track,trigger)=>{ return { get(){ track() // 收集依赖 return value } set( newValue ){                 clearTimeout(timer)                 timer = setTimeout(()=>{                     console.log('触发------')     value = newValue                     timer = null     trigger() // 触发依赖                                },500) } } }) }

ref 获取dom元素

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template> <div> <div>test</div> <div ref="fetchTest">{{ user }}</div> <button @click="change">修改</button> </div> </template> <script setup lang="ts"> import { ref } from 'vue' const fetchTest = ref<HTMLDivElement>() const user = ref({ name: 'Fish' }) const change = () => { user.value.name = '我要被修改了' console.log(fetchTest.value?.innerText) } </script> <style scoped></style>

源码:core/packages/src/ref.ts

ref与reactive如何选择

使用 ref基础类型值(StringNumberBooleanSymbol) 或单值对象【即:只有一个属性值的对象】(如:{ count: 1 })

使用 reactive引用类型值(ObjectArrayMapSetWeakMapWeakSet)

ref 与reactive使用

ref 与 reactive 都是把变量变成响应式变量,使用ref或者reactive对其进行包裹

复制代码
1
2
3
4
// 示例 let user.name = ref("Fish")    // ref 支持所有类型 let form = reactive("Fish")    // 不能使用string类型,所以出错 let form = reactive({name:'Fish',age:18})    // 正确表示

reactive

reactive 深层次响应

一般在复杂的数据类型使用。使用reactive取值或赋值(CURD)时无需.value

复制代码
1
2
3
4
5
6
7
type U = { name:string,age:number } let form = reactive<U>({     name:"Fish",     age:18 }) //  修改值 form.age = 28

方案一:接收泛型

复制代码
1
2
type U = { name:string,age:number } const user = reactive<U>({name:"Fish"}) // reactive<U>( )

方案二:自动推断

对象

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template> <div> <input v-model="form.name" type="text" /> <hr /> <input v-model="form.age" type="text" /> <hr /> <button @click.prevent="submit">提交</button>     <!-- @click.preven 参考Vue .sync修饰符 --> </div> </template> <script setup lang="ts"> import { reactive } from 'vue' let form = reactive({ name: 'Fish', age: 18 }) const submit = () => { console.log(form) } </script> <style scoped></style>

数组

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template> <div> <ul> <li :key="index" v-for="(item, index) in list">{{ item }}</li> </ul> <hr /> <button @click="add">添加</button> </div> </template> <script setup lang="ts"> import { reactive } from 'vue' let list = reactive<string[]>([]) // string[] string类型的数组 const add = () => { // 添加方式有2种 // 使用push(),在数组末尾添加新项;使用unshift(),在数组开头添加新项 list.push('hello world') } </script> <style scoped></style>

如果是调用接口,点击添加,不显示?

因为reactive是一个proxy代理的对象,直接赋值的话,就覆盖proxy对象了,从而会破坏reactive的proxy对象。

所以不能直接赋值,否则破坏响应对式对象了。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template> <div> <ul> <li :key="index" v-for="(item, index) in list">{{ item }}</li> </ul> <hr /> <button @click="add">添加</button> </div> </template> <script setup lang="ts"> import { reactive } from 'vue' let list = reactive<string[]>([]) // string[] string类型的数组 const add = () => { setTimeout(() => { // res为接口调用的数据 let res = ['vue', 'typescript', 'nestjs', 'vite', 'pinia'] // 直接赋值 list = res console.log(list) }, 500) } </script> <style scoped></style>
解决方案一
复制代码
1
2
3
4
// 直接赋值 list = res // 修改为 list.push(...res)
解决方案二、三

添加一个对象arr,把数组作为一个属性

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 原代码 // let list = reactive<string[]>([]) // 代码修改为 let list = reactive<{ arr: string[] }>({ arr: [] }) // 同时调整 // <li :key="index" v-for="(item, index) in list">{{ item }}</li> // 调整后内容 <li :key="index" v-for="(item, index) in list.arr">{{ item }}</li> // -------------------------------- // 原代码 // list.push(...res) // 修改为 list.arr = res // 或者修改为 list.arr.push(...res)
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template> <div> <ul> <li :key="index" v-for="(item, index) in list.arr">{{ item }}</li> </ul> <hr /> <button @click="add">添加</button> </div> </template> <script setup lang="ts"> import { reactive } from 'vue' //let list = reactive<string[]>([]) // 解决方案二、三: let list = reactive<{ arr: string[] }>({ arr: [] }) const add = () => { setTimeout(() => { let res = ['vue', 'typescript', 'nestjs', 'vite', 'pinia'] // list.push(...res) // 解决方案二:list.arr = res list.arr = res     // 解决方案三:     list.arr.push(...res) console.log(list) }, 500) } </script> <style scoped></style>

readyonly 只读属性

readonly 属性强制赋值不改变;如果原始对象变化,则改变

复制代码
1
2
3
4
let obj = reactvie({name:'Fish'}) const read = readonly(obj) read.name = 'Fisher'    // 无法分配到 "name" ,因为它是只读属性。 obj.name = 'Fisher'    // 则,obj、read 都将改变

shallowReactive 浅层次响应

参考shallowRef,原理相同

toRef

  • 针对一个响应式对象(reactive 封装)的 prop(属性)创建一个ref,且保持响应式

  • 两者 保持引用关系

toRefs

toRefs 是一种用于破坏响应式对象并将其所有属性转换为 ref 的实用方法

  • 将响应式对象(reactive封装)转成普通对象

  • 对象的每个属性(Prop)都是对应的ref

  • 两者保持引用关系

ref和toRef的区别

ref

toRef

拷贝,修改响应式数据不会影响原始数据

引用,修改响应式数据会影响原始数据

ref数据发生改变,视图自动更新

只能修改响应对象的值

非响应式对象使用toRef视图无变化

创建一个响应式的数据对象,传入的为基本数据类型

接收两个参数

第一个参数是对象,第二个参数是对象的属性

toRef 、toRefs、toRaw

toRef

如果是ref 对象,直接返回;否则,创建一个类ref 对象

类ref 对象只是做了值的改变,并未处理收集依赖触发依赖的过程。所以,普通对象无法更新视图。

如果原始对象是响应式的,则会更新视图并改变数据

复制代码
1
2
3
4
const obj = {name:'Fish',age:18} // obj 为普通对象 const res = toRef(obj,'age') // age 转化为响应式对象

toRefs

批量创建ref对象(普通对象),方便解构

当想解构reactive对象时,记得使用toRefs,如果直接解构是没办法使用响应式的

toRefs接收一个对象作为参数,遍历reactive对象的所有属性,使其成为ref对象,然后循环调用toRef

复制代码
1
2
const obj = reactvie({name:'Fish',age:18}) let { name , age } = toRefs(obj)

toRaw

将响应式对象转化为普通对象。使用场景:不想改变视图时使用

通过 ReactiveFlags 枚举值 取出 proxy 对象的原始对象,脱离proxy对象

RAW = '__v_raw'

复制代码
1
2
3
4
5
const obj = reactvie({name:'Fish',age:18}) const res = toRaw(obj) // 响应式对象转化为普通对象 // 其实就是 // const res = obj['_v_raw']

参考来源

小满教程 https://www.bilibili.com/video/BV1dS4y1y7vd

感谢小满,一键三连。

最后

以上就是虚拟棒球最近收集整理的关于vue3响应式之ref、reactive、toRef、toRefs、toRawrefref与reactive如何选择ref 与reactive使用reactivetoReftoRefsref和toRef的区别toRef 、toRefs、toRaw的全部内容,更多相关vue3响应式之ref、reactive、toRef、toRefs、toRawrefref与reactive如何选择ref内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部