避大坑!Vue3中reactive丢失响应式的问题

在vue3中,我们定义响应式数据无非是ref和reactive。
但是有的小伙伴会踩雷!导致定义的响应式丢失的问题。

reactive丢失响应式的情况1(直接赋值)

javascript 复制代码
`场景:
1.你定义了一个数据:let data=reactive({
          name:"",
          age:""
})
2.然后你请求了接口,赋值给data
let res=await getUserApi();  //请求接口
data=res.data;                     //将返回的结果赋值给data`

大错特错!!!

reactive丢失响应式的情况2(解构赋值)

javascript 复制代码
`场景:
1.你定义了一个数据:let data=reactive({
          name:"",
          age:""
})
2.然后你解构了
let {name}=data; //解构赋值`

大错特错!!!

了解响应式

1.ref 定义数据(包括对象)时,都会变成 RefImpl(Ref 引用对象) 类的实例,无论是修改还是重新赋值都会调用 setter,都会经过 reactive 方法处理为响应式对象。

2.但是 reactive 定义数据(必须是对象),是直接调用 reactive 方法处理成响应式对象。如果重新赋值,就会丢失原来响应式对象的引用地址,变成一个新的引用地址,这个新的引用地址指向的对象是没有经过 reactive 方法处理的,所以是一个普通对象,而不是响应式对象。解构同理。

避坑办法:

  1. 避开直接赋值和结构,reactive直接包裹一个对象。
javascript 复制代码
`let data=reactive({
    userData:{}        //里面定义一个对象,这样赋值就不会丢失响应式了。
})

//获取接口数据
let res=await getUserApi();  //请求接口
data.userData=res.data;      //将返回的结果赋值给data`
  1. 简单数据类型使用ref()来进行定义。

拔高:TS对reactive里对象进行限制

上面那种情况是没在TS限制的情况下我们解决的,但是有TS用户就有疑问了,这样我在reactive内部再定义一个对象,就失去了对userData的类型限制了,怎么办呢?

答案:写类!!!!!!!!!!!!!!!!!!!

下面我们就来研究一下:

1.我们最开始会可能这样对data加上类型限制:

javascript 复制代码
`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

javascript 复制代码
`//1.定义限制userData的接口
export interface dataRule{
    name:string,
    age:number
}

//写类
export class data{
    //定义userData并且做TS限制和赋初始值
    userData:dataRule={
        name:"",
        age:""
    }
}`

在对应的.vue文件中引入该类。

javascript 复制代码
`//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

相关推荐
Yhame.14 分钟前
【使用层次序列构建二叉树(数据结构C)】
c语言·开发语言·数据结构
言之。20 分钟前
【Go语言】RPC 使用指南(初学者版)
开发语言·rpc·golang
小墨宝29 分钟前
js 生成pdf 并上传文件
前端·javascript·pdf
HED1 小时前
用扣子快速手撸人生中第一个AI智能应用!
前端·人工智能
DN金猿1 小时前
使用npm install或cnpm install报错解决
前端·npm·node.js
丘山子1 小时前
一些鲜为人知的 IP 地址怪异写法
前端·后端·tcp/ip
投笔丶从戎1 小时前
Kotlin Multiplatform--01:项目结构基础
android·开发语言·kotlin
志存高远661 小时前
Kotlin 的 suspend 关键字
前端
www_pp_1 小时前
# 构建词汇表:自然语言处理中的关键步骤
前端·javascript·自然语言处理·easyui
YuShiYue2 小时前
pnpm monoreop 打包时 node_modules 内部包 typescript 不能推导出类型报错
javascript·vue.js·typescript·pnpm