Vue3系列4--ref和reactive响应式
1 ref
接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value
property,指向该内部值。
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <template> <div> <button @click= "changeMsg" >change</button> <div>{{ message }}</div> </div> </template> <script setup lang= "ts" > let message: string = "我是message" const changeMsg = () => { message = "change msg" } </script> <style> </style> |
我们这样操作是无法改变message 的值 应为message 不是响应式的无法被vue 跟踪要改成ref。响应式就是在页面上实时显示修改的值。
Ref TS对应的接口:
1 2 3 | interface Ref<T> { value: T } // 对于接口问题,是TS语法,如果不清楚,直接看TS |
但是被ref包裹后需要使用value来进行赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <template> <div> <button @click= "changeMsg" >change</button> <div>{{ message }}</div> </div> </template> <script setup lang= "ts" > import {ref,Ref} from 'vue' let message:Ref<string> = ref( "我是message" ) let message= ref<string>( "我是message" ) // 第二种方式const changeMsg = () => { message.value = "change msg" } </script> <style> </style> |
2 isref
判断是不是一个ref对象1 2 3 4 5 6 7 8 | import { ref, Ref,isRef } from 'vue' let message: Ref<string | number> = ref( "我是message" ) let notRef:number = 123 const changeMsg = () => { message.value = "change msg" console.log(isRef(message)); //true console.log(isRef(notRef)); //false } |
3 shallowref
创建一个跟踪自身 .value
变化的 ref,但不会使其值也变成响应式的
例子1
修改其属性是非响应式的这样是不会改变的
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> <button @click= "changeMsg" >change</button> <div>{{ message }}</div> </div> </template> <script setup lang= "ts" > import { Ref, shallowRef } from 'vue' type Obj = { name: string } let message: Ref<Obj> = shallowRef({ name: "唐少" }) const changeMsg = () => { message.value.name = '唐少2' } </script> <style> </style> |
例子2
这样是可以被监听到的修改value,必须要修改整个对象才行
1 2 3 4 5 6 7 8 9 10 11 | import { Ref, shallowRef } from 'vue' type Obj = { name: string } let message: Ref<Obj> = shallowRef({ name: "唐少" }) const changeMsg = () => { message.value = { name: "唐少2" } } |
4 triggerRef
为了解决shallowRef的问题,我们强制更新页面DOM,这样也是可以改变值的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <template> <div> <button @click= "changeMsg" >change</button> <div>{{ message }}</div> </div> </template> <script setup lang= "ts" > import { Ref, shallowRef,triggerRef } from 'vue' type Obj = { name: string } let message: Ref<Obj> = shallowRef({ name: "唐少" }) const changeMsg = () => { message.value.name = '唐2' triggerRef(message) } </script> <style> </style> |
5 customRef
自定义ref ,customRef 是个工厂函数要求我们返回一个对象 并且实现 get 和 set
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 | <script setup lang= "ts" > import { Ref, shallowRef, triggerRef, customRef } from 'vue' function Myref<T>(value: T) { return customRef((track, trigger) => { return { get() { track() return value }, set(newVal: T) { console.log( 'set' ); value = newVal trigger() } } }) } let message = Myref( '唐少' ) const changeMsg = () => { message.value = '唐少2' // triggerRef(message) } </script> |
6 reactive
用来绑定复杂的数据类型 例如 对象 数组
reactive 源码约束了我们的类型,类型必须是object,不能绑定普通的类型,会报错。你如果用ref去绑定对象 或者数组等复杂的数据类型 我们看源码里面其实也是 去调用reactive,但使用reactive 去修改值无须.value
- reactive 基础用法
1 2 3 4 5 | import { reactive } from 'vue' let person = reactive({ name: "唐少" }) person.name = "唐少2" |
- 数组异步赋值问题
1 2 3 4 5 6 | // 这样赋值页面是不会变化的因为会脱离响应式<br>let person = reactive<number[]>([]) setTimeout(() => { person = [1, 2, 3] console.log(person); },1000) |
- 解决方案1:push
1 2 3 4 5 6 7 8 | import { reactive } from 'vue' let person = reactive<number[]>([]) setTimeout(() => { const arr = [1, 2, 3] person.push(...arr) console.log(person); },1000) |
- 解决方案2:包裹一层对象
1 2 3 4 5 6 7 8 9 10 11 12 | type Person = { list?:Array<number> } let person = reactive<Person>({ list:[] }) setTimeout(() => { const arr = [1, 2, 3] person.list = arr; console.log(person); },1000) |
7 readonly
拷贝一份proxy对象将其设置为只读
1 2 3 4 5 | import { reactive ,readonly} from 'vue' const person = reactive({count:1}) const copy = readonly(person) //person.count++ copy.count++ |
8 shallowReactive
只能对浅层的数据 如果是深层的数据只会改变值 不会改变视图
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 33 34 35 36 | <template> <div> <div>{{ state }}</div> <button @click= "change1" >test1</button> <button @click= "change2" >test2</button> </div> </template> <script setup lang= "ts" > import { shallowReactive } from 'vue' const obj = { a: 1, first: { b: 2, second: { c: 3 } } } const state = shallowReactive(obj) function change1() { state.a = 7 } function change2() { state.first.b = 8 state.first.second.c = 9 console.log(state); } </script> <style> </style> |
9 toRef
如果原始对象是非响应式的就不会更新视图 数据是会变的,如果原始对象是响应式的是会更新视图并且改变数据的
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> <button @click= "change" >按钮</button> {{state}} </div> </template> <script setup lang= "ts" > import { reactive, toRef } from 'vue' const obj = { foo: 1, bar: 1 } const state = toRef(obj, 'bar' ) // bar 转化为响应式对象 const change = () => { state.value++ console.log(obj, state); } </script> |
10 toRefs
可以帮我们批量创建ref对象主要是方便我们解构使用
1 2 3 4 5 6 7 8 9 10 | import { reactive, toRefs } from 'vue' const obj = reactive({ foo: 1, bar: 1 }) let { foo, bar } = toRefs(obj) foo.value++ console.log(foo, bar); |
11 toRaw
将响应式对象转化为普通对象
1 2 3 4 5 6 7 8 9 10 11 12 13 | import { reactive, toRaw } from 'vue' const obj = reactive({ foo: 1, bar: 1 }) const state = toRaw(obj) // 响应式对象转化为普通对象 const change = () => { console.log(obj, state); } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性