在vue3中,我们定义响应式数据无非是ref和reactive。
但是有的小伙伴会踩雷!导致定义的响应式丢失的问题。
reactive丢失响应式的情况1(直接赋值)
场景:1.你定义了一个数据:let data=reactive({name:"",age:""})2.然后你请求了接口,赋值给datalet res=await getUserApi();//请求接口data=res.data; //将返回的结果赋值给data
大错特错!!!
reactive丢失响应式的情况2(解构赋值)
场景:1.你定义了一个数据:let data=reactive({name:"",age:""})2.然后你解构了let {name}=data; //解构赋值
大错特错!!!
了解响应式
1.ref 定义数据(包括对象)时,都会变成 RefImpl(Ref 引用对象) 类的实例,无论是修改还是重新赋值都会调用 setter,都会经过 reactive 方法处理为响应式对象。
2.但是 reactive 定义数据(必须是对象),是直接调用 reactive 方法处理成响应式对象。如果重新赋值,就会丢失原来响应式对象的引用地址,变成一个新的引用地址,这个新的引用地址指向的对象是没有经过 reactive 方法处理的,所以是一个普通对象,而不是响应式对象。解构同理。
避坑办法:
避开直接赋值和结构,reactive直接包裹一个对象。
let data=reactive({userData:{}//里面定义一个对象,这样赋值就不会丢失响应式了。})//获取接口数据let res=await getUserApi();//请求接口data.userData=res.data;//将返回的结果赋值给data
简单数据类型使用ref()来进行定义。
拔高:TS对reactive里对象进行限制
上面那种情况是没在TS限制的情况下我们解决的,但是有TS用户就有疑问了,这样我在reactive内部再定义一个对象,就失去了对userData的类型限制了,怎么办呢?
答案:写类!!!!!!!!!!!!!!!!!!!
下面我们就来研究一下:
1.我们最开始会可能这样对data加上类型限制:
interface dataRule{name:string,age:number}//定义数据let data:dataRule=reactive({name:"",age:""})//但是,当获取接口的时候let res=await getUserApi();//请求接口//data=res.data; //我们已经知道不能这样写了,会丢失响应式。(xxx达咩)//2.这时聪明的你可能会这样data.name=res.data.name;data.age=res.data.age;//PS://问题一:赋值太麻烦//这样确实可以不损坏响应式,但是如果我说你这里面不仅仅有name和age呢,而是有很多很多,那咋办?//问题二:无法对userData做类型限制//你可能又想这样:let data=reactive({ userData:{}})这样写,我们怎么能对userData做类型限制呢?
实现:分开写类!!!!!!!!!!!(重点来啦)
1.单独拿出来一个ts文件,比如user.ts
//1.定义限制userData的接口export interface dataRule{name:string,age:number}//写类export class data{//定义userData并且做TS限制和赋初始值userData:dataRule={name:"",age:""}}
在对应的.vue文件中引入该类。
//1.引入刚写好ts类文件import {dataRule,data} from "@/type/user.ts"//2.重点来了,我实例化出来data,然后用一个变量User接收。let User=reactive(new data());/*//实例化出来以后相当于这样的结构:User={userData:{name:"",age:""}}*///3.我们调用接口//获取接口数据let res=await getUserApi();//请求接口User.userData=res.data;//将返回的结果赋值给data,这样也不会丢失响应式,并且userData也受了TS的限制。
结语:
在前端的道路上,我们就是要不断地保持学习,然后逐渐的变强大,沉淀自己,我们顶峰相见。
–Yan