【聚焦前端实战】Vue3响应式问题,数据明明已经改变但是视图页面上没有刷新?

1,191 阅读3分钟

“我正在参加「掘金·启航计划」”

大家好,欢迎来到【聚焦前端实战】系列专栏,我是江子麟

有些时候大家会碰到这样一个问题,数据明明已经改变但是视图页面上没有刷新?这个问题出现相当头痛,有时候并不好排查,特别是有些对异步、事件循环不太清楚的同学,在拿到后端的给的数据时常会遇到这种情况。

事件循环、异步、宏任务微任务 指路

首先要了解Vue3中响应式

一般对于数据来说,我们一般定义的时候使用ref()reactive() 下面我们先简单的介绍一下这两位。

ref()

接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value


function ref<T>(value: T): Ref<UnwrapRef<T>>

interface Ref<T> {
  value: T
}

//选自官网 js则无类型就可以

ref 对象是可更改的,也就是说你可以为 .value 赋予新的值。它也是响应式的,即所有对 .value 的操作都将被追踪,并且写操作会触发与之相关的副作用。

如果将一个对象赋值给 ref,那么这个对象将通过 reactive()转为具有深层次响应式的对象。这也意味着如果对象中包含了嵌套的 ref,它们将被深层地解包。

若要避免这种深层次的转换,请使用 shallowRef()来替代。

reactive()

返回一个对象的响应式代理。

function reactive<T extends object>(target: T): UnwrapNestedRefs<T>

//js去掉类型就可以了

响应式转换是**“深层”的:它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性**,同时保持响应性

值得注意的是,当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包。

若要避免深层响应式转换,只想保留对这个对象顶层次访问的响应性,请使用 **shallowReactive()** 作替代。

以上内容大多来自于Vue.js官网 具体示例请移步官网。

总结(说人话的来讲):

基础类型ref() 来将其形成响应式,如果需要使用或者更改或者说拿到这个数时,则用.value 来响应式的取得和更改的操作。

但是如果是对象的话,还是建议使用reactive() 包裹对象来使用。

我用了响应式,但是数据打印出来更新了可是视图没有更新

上面我们已经学会了1+1,接下来该开始造火箭了。

嵌套多层类型

一般上面那种情况的出现可能不是简单的 ref(”string”)reactive({count: 0}) 在实际的生产过程中,接口给我们的数据里,我们经常会见到这种样子的数据(对象组成的数组)

//接口返回的res

{
	staus:200,
	message:"数据请求成功",
	data:[
		{
			phone:"12345678",
			name:"张三",
		},
		{
			phone:"12345578",
			name:"张四",
		}
	]
}

//稍简单一点的 对象里面的数组也同理

这种情况下我们想给他实现响应式就较为困难,数组也是对象,可能首先想到的就是reactive([]) 不过这还是无法形成响应式

以这个为例的话我们有三种解决方案:

第一种:

个人建议的方式

const state = reactive({
  arr: []
});
 
state.arr = [1, 2, 3];
state.arr = res.data;

第二种:

不太建议的方式,前面说了最好基础类型才用ref()

const state = ref([])
 
state.value = [1, 2, 3]

第三种:

中规中矩的方式

const arr = reactive([])
 
arr.push(...res.data)

第一种和第三种方式笔者实战已经是可以的,第二种方式不推荐。

另外对象同理,如下所示。

const state = reactive({
  arr: {}
});
 

写在最后

到了现在在Vue3的setup中的响应式基本都够用了,比较有难度的嵌套多层的响应式也按这种思路基本可以去实现了。