踩坑:Vue 模版中用到的响应式数据,不要在异步操作中给出声明

问题描述
2023/06/04
今天在学习时,看黑马的视频,小兔鲜的前端项目。
目标 数据是对象数组类型,但是视频中将目标数据使用ref()来生成
心里很不得劲,因为在我的习惯中,只有基本数据类型才用ref(),对象和数组类型要使用reactive()
这个目标数据是通过异步请求获取到的,在异步请求的会调函数中,完成对响应式数据的赋值。
视频中完整的代码是这样的:

<script setup>
	// 导入封装的异步api
	import { getCategoryAPI } from '@/api/home'
	import { ref } from 'vue'
	// 定义响应式数据
	const category = ref([])
	// 封装请求函数
	async function getCategory(){
		const res = await getCategory()
		// 赋值
		// res.result是一个普通数组
		category.value = res.result
	}
	
</script>
<template>
<!-- 渲染数据 -->
	<ul>
		<li v-for="item in category" :key="item.id">
			...
		</li>
	</ul>
</template>

这个代码执行起来是没有问题的,成功拿到数据,页面成功渲染。
我想要通过reactive()来定义,然后我的代码是这样的
我是这样想的:

  1. 如果代码是这样的
import { reactive } from 'vue'

// 定义响应式数据
const category = reactive([])
async function getCategory(){
	const res = await getCategoryAPI()
	// category失去响应式
	category = res.result
}
  1. 如果代码是这样
import { reactive } from 'vue'

// 定义响应式数据
const category = reactive([])
async function getCategory(){
	const res = await getCategoryAPI()
	// 等于重新创建了一个响应式对象
	// 虽然可以实现响应式数据
	// 但是之前的那个空数组就浪费了
	// 所以我不想这样
	category = reactive(res.result)
}

最终经过我的“深思熟虑”,代码是这样的

import { reactive } from 'vue'

// 定义一个数据
const category 
async function getCategory(){
	const res = await getCategoryAPI()
	// 此时赋值并规定category是一个响应式的数据
	category = reactive(res.result)
}

这样做的问题是:可以成功获取到数据,通过Devtools调试发现,category也是一个响应式数据,但是页面渲染不出来
纳闷了~~~

解析
一开始,我以为是reactive()函数与异步请求的有冲突,哈哈~~
晚上吃饭的时候,突然想到了。
分析:

  1. 浏览器在执行 到此异步请求函数时,发现是异步的,就不管了,继续解析下面的代码
  2. 当解析到模版时,此时的category还只是一个普通变量,不是响应式数据,而且是空的
  3. 页面当做普通的变量来渲染,所以页面不会渲染出来
  4. 当异步请求完成时,此时category才是响应式的了,但是并不会触发页面的重新渲染,只有当这个category中的内容被修改时,我们页面才将数据渲染出来。
    都是基础知识不牢固惹的祸。
    ● 在视频中的代码,异步请求前,就规定了category这个变量是响应式的了,
    ● 模版此时解析的是一个响应式数据
    ● 当异步请求结束后,category中有了数据,模版重新渲染。

改进
所以,要想使用reactive()来接收响应式数据数组,而且又不想浪费空间,可以这样
● 先将category定义为响应式数据
● 在异步请求中,将接收的数据追加到category中

const category = reactive([])

async function getCategory(){
	const res = await getCategoryAPI()
	category.push(...res.result)
}

总结
模版要用到的响应式数据,不要在异步操作中定义/声明成响应式,而是应该在异步请求前完成对响应式的定义、声明。

你可能感兴趣的:(BUG\踩坑,vue.js,javascript,前端)