vue3父组件异步获取后端数据,子组件无法及时渲染问题分析、解决及使用suspense组件进行骨架屏优化

article/2025/10/13 2:37:23

vue3中一个常见场景,父组件向后端异步获取数据,再父子传参给子组件,由子组件来渲染获取到的数据。

简单的props父子传参

只用props进行父子传参,子组件在其一系列生命周期开始时是获取不到数据的。父子组件的生命周期流程如下:
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
生命周期钩子是同步执行的,而向后端获取数据是异步的,如果在父组件的created中向后端异步获取数据,根据事件循环的顺序,子组件开始创建时是获取不到数据的。

做一个实现进行验证

//父组件,getArticleById向后端获取数据
const initArticleForm = () => {console.log('父组件created')getArticleById(articleId).then(res => {console.log('父组件获取到数据')})
}
initArticleForm()
onMounted(()=>{console.log('父组件Mounted')
})

在这里插入图片描述
可以看到放在父created中的异步获取要到父mounted后才能拿到数据。这样子组件是无法正常渲染的。

解决方案

1、使用v-if控制子组件开始挂载的时机

当异步获取到数据后再用v-if设置为true挂载子组件

<RichTextEditor v-if="flag" v-model="addArticleForm.content" ></RichTextEditor>
const initArticleForm = () => {console.log('父组件created')getArticleById(props.articleId).then(res => {flag.value = true //获取到数据改变flaglet endTime = window.performance.now()console.log('父组件获取到数据')})
}
initArticleForm()

在这里插入图片描述
此时可以看到顺序是正确的,所以可以正常显示

性能测试

为了模拟卡顿的环境,将后端接口延迟3s返回

getArticleContentById: async (req, res) => {const {id} = req.queryconst data = await ArticleService.getArticleContentById(id)await setTimeout(()=>{res.header("Cache-Control", "no-cache, no-store, must-revalidate");res.send({code: 200,msg: "获取成功",data})}, 3000)},

然后在组件中v-for出1000个相同div用来展示父组件传来的数据

<div v-for="item in list">{{props.modelValue}}</div>
<script setup>
let list = []
for(let i = 0; i < 10000; i++){list.push(i)
}
</script>

子组件白屏时间计算:请求数据所需要的时间+子组件渲染的时间
在这里插入图片描述
共3104+109ms

2、子组件中用watch更新

用watch监视props变化,并通知试图对应的数据变化

let startTime = window.performance.now()
console.log('子组件created')
onMounted(()=>{console.log(`子组件Mounted`)
})
const props = defineProps({modelValue: {type: String,default: ""}
})
watch(()=>props.modelValue, (newValue, oldValue) => {valueEditor.value = props.modelValue//更新数据console.log('watch到新数据并更新页面')let endTime = window.performance.now()console.log(`子组件加载白屏时间:${endTime-startTime}`)
})

在这里插入图片描述
在这里插入图片描述

此时子组件白屏时间的计算方式不再是请求数据时间+子组件渲染时间,因为子组件会在数据请求到达之前渲染完毕,在数据到达之后再更新对应dom节点,此时白屏时间为111ms,等待视图更新成获取到的数据,时间总共为3132ms。

3、子组件中用computed更新

let valueEditor = computed(()=>{let endTime = window.performance.now()console.log(`子组件最终更新时间:${endTime-startTime}`)return props.modelValue
})

原理同watch基本一致,加载时间为58ms,最终更新时间为3114ms
在这里插入图片描述
在这里插入图片描述

可以看到使用computed的加载时间是要比watch快的,因为为了测试,在组件中v-for出1000个相同div用来展示父组件传来的数据,用computed有缓存这1000个div用的都是同一个缓存所以比较快。

骨架屏优化

使用suspense内置组件,要将原来的父组件放在suspense的插槽中,当数据没有加载到位时显示#fallback中的组件

<template><Suspense><template #default><parent></parent></template><template #fallback><div>loading...这里放骨架屏的组件</div></template></Suspense>
</template><script setup>
import {defineAsyncComponent} from "vue";
const parent= defineAsyncComponent(()=>import('./updateItem.vue'))
</script>

parent组件

<template><el-form :model="addArticleForm" label-width="120px" ref="addArticleFormRef" :rules="addArticleFormRule"><el-form-item label="文章标题" class="form-item" prop="title"><el-input class="upload-input" v-model="addArticleForm.title" placeholder="请输入文章标题"/><el-button type="primary" class="upload-btn" @click="upload(addArticleFormRef)"><span v-if="!loading">修改文章</span><span v-else>上 传 中...</span><el-icon class="el-icon--right"><Upload /></el-icon></el-button></el-form-item><el-form-item label="文章分类" class="form-item" prop="tag"><el-select v-model="addArticleForm.tag" placeholder="请选择文章分类"><el-option v-for="key in user().articleTag.keys()" :label="key" :value="user().articleTag.get(key)"></el-option></el-select></el-form-item><el-form-item label="文章内容" class="form-item"><RichTextEditor  v-model="addArticleForm.content" v-model:textValue="addArticleForm.abstract"></RichTextEditor></el-form-item></el-form>
</template><script setup>
import RichTextEditor from "../../../components/RichTextEditor.vue";
import {ref, reactive} from "vue";
import {user} from "../../../store/index.js";
import {addArticle} from "../../../api/system.js";
import {getArticleById} from '../../../api/article.js'
import {useRouter,useRoute} from "vue-router";
const route = useRoute()const addArticleForm = reactive({tag: null, //Number类型title: '',content: null,
})//请求数据,setup语法糖中使用顶层await,setup会自动在模块顶层加async,用await控制suspense组件中替换骨架屏的时机
let {data} = await getArticleById(route.params.articleId)//向后端请求
addArticleForm.tag = data[0].tag
addArticleForm.title = data[0].title
addArticleForm.content = data[0].content
</script>

此时父组件的子组件不再需要v-if ,watch,computed,可以直接用props中的数据


http://chatgpt.dhexx.cn/article/GVDqfCr1.shtml

相关文章

Vue3尝鲜之Suspense异步组件(踩坑)

Suspense组件是Vue3中的知名功能之一。 它们允许我们的应用程序在等待异步组件时渲染一些后备内容&#xff0c;可以让我们创建一个平滑的用户体验。 值得庆幸的是&#xff0c;Suspense组件非常容易理解&#xff0c;它们甚至不需要任何额外的导入! 可以解决异步请求的困境&…

Vue——vue3 suspense async await用法 onErrorCaptured 抓取错误

子组件 my-project\src\components\DogShow.vue <template><img :src"result && result.message" /> </template><script lang"ts"> import axios from "axios"; import { defineComponent } from "vue&…

React18介绍及setState、suspense、useTransition、useDeferredValue的使用

文章目录 1. 带来了什么2. 创建项目3. 入口文件的改变4. setState5. 条件渲染传异步数据给子组件6. suspense结合异步组件实现条件渲染7. useTransition降级渲染8. useDeferredValue节流处理 1. 带来了什么 改进已有属性&#xff0c;如自动批量处理【setState】、改进Suspense…

【VUE】vue3学习笔记(异步组件,包含defineAsyncComponent、Suspense的使用)

&#x1f431; 个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️ 作者简介&#xff1a;2022年度博客之星前端领域TOP 2&#xff0c;前端领域优质作者、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &am…

Vue3——Suspense组件

Suspense组件 官网中有提到他是属于实验性功能&#xff1a; <Suspense> 是一项实验性功能。它不一定会最终成为稳定功能&#xff0c;并且在稳定之前相关 API 也可能会发生变化。 <Suspense> 是一个内置组件&#xff0c;用来在组件树中协调对异步依赖的处理。它让我…

vue3中的Suspense

1、Suspense作用 等待异步组件时渲染一些额外内容&#xff0c;让应用有更好的用户体验 2、使用步骤 使用步骤&#xff1a; 异步引入组件 import {defineAsyncComponent} from vue const Child defineAsyncComponent(()>import(./components/Child.vue)) 使用Suspense包裹组…

react-Suspense工作原理分析

Suspense 基本应用 Suspense 目前在 react 中一般配合 lazy 使用&#xff0c;当有一些组件需要动态加载(例如各种插件)时可以利用 lazy 方法来完成。其中 lazy 接受类型为 Promise<() > {default: ReactComponet}> 的参数&#xff0c;并将其包装为 react 组件。React…

vue3新增Suspense组件

在开始介绍Vue的Suspense组件之前&#xff0c;我们有必要先了解一下React的Suspense组件&#xff0c;因为他们的功能类似。 React React 16.6 新增了 <Suspense> 组件&#xff0c;让你可以“等待”目标代码加载&#xff0c;并且可以直接指定一个加载的界面&#xff08;…

Suspense组件

先上官网&#xff1a;https://cn.vuejs.org/guide/built-ins/suspense.html 注意一下 <Suspense> 是一项实验性功能。它不一定会最终成为稳定功能&#xff0c;并且在稳定之前相关 API 也可能会发生变化。 在使用了之后在浏览器控制台会有如下打印&#xff0c;至少目前是…

详解Vue3 Suspense:是什么?能干什么?如何用?

本篇文章带大家深入了解一下Vue3 Suspense&#xff0c;聊聊Suspense是什么、能干什么&#xff0c;以及如何使用它&#xff0c;希望对大家有所帮助&#xff01; Suspense 不是你想的那样。是的&#xff0c;它帮助我们处理异步组件&#xff0c;但它的作用远不止于此。&#xff0…

Vue3.0的新特性(8)Suspense

Suspense是Vue3推出的一个内置组件&#xff0c;它允许我们的程序在等待异步组件时渲染一些后备的内容&#xff0c;可以让我们创建一个平滑的用户体验&#xff1b;Vue中加载异步组件其实在Vue2.x中已经有了&#xff0c;我们用的vue-router中加载的路由组件其实也是一个异步组件&…

实现分布式锁的解决方案

目录 1. 分布式锁1.1 什么是分布式锁1.2 为什么要使用分布式锁1.3 分布式锁应具有的特性 2 分布式锁实现方案2.1 数据库实现分布式锁2.2 ZooKeeper实现分布式锁2.3 Redis实现分布式锁2.3.1 版本一2.3.2 版本二2.3.3 版本三 3. Redisson3.1 Redisson介绍3.2 Redisson分布式锁使用…

什么是分布式锁,分布式锁有什么作用?

1 、什么是分布式锁 为了防止分布式系统中的多个进程之间相互干扰&#xff0c;我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。 2、为什么要使用分布式锁 成员变量 A 存在 JVM1、JVM2、JVM3 三个 JVM 内存中&#xff1b…

分布式锁以及三种加锁方式

在很多场景中&#xff0c;我们为了保证数据的最终一致性&#xff0c;需要很多的技术方案来支持&#xff0c;比如分布式事务、分布式锁等。那具体什么是分布式锁&#xff0c;分布式锁应用在哪些业务场景、如何来实现分布式锁呢&#xff1f; 一 为什么要使用分布式锁 我们在开发…

分布式架构 --- 分布式锁

分布式锁 1. 研究背景及其意义2. 分布式锁的介绍2.1 分布式锁2.2 为什么需要分布式锁2.3 分布式锁的基本要求 3. 分布式锁的实现3.1 基于数据库的分布式锁3.1.1选用数据库实现分布式锁的原因3.1.2 基于数据库实现分布式锁的缺点3.1.3分布式锁的实现 3.2 基于Redis的分布式锁3.2…

分布式锁的区别

分布式锁&#xff0c;是一种思想&#xff0c;它的实现方式有很多。比如&#xff0c;我们将沙滩当做分布式锁的组件&#xff0c;那么它看起来应该是这样的 加锁 在沙滩上踩一脚&#xff0c;留下自己的脚印&#xff0c;就对应了加锁操作。其他进程或者线程&#xff0c;看到沙滩上…

分布式锁的实现方式

背景 分布式场景中的数据一致性问题一直是一个比较重要的话题。分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;和分区容错性&#xff08;Partition tolerance&#xff09…

分布式锁-Redisson

分布式锁 1、分布式锁1.1 本地锁的局限性1.1.1 测试代码1.1.2 使用ab工具测试(单节点)1.1.3 本地锁问题演示(集群情况) 1.2 分布式锁实现的解决方案1.3 使用Redis实现分布式锁(了解即可)1.3.1 编写代码1.3.2 压测 1.4 使用Redisson解决分布式锁1.4.1 实现代码1.4.1 压测1.4.2 可…

Redis 分布式锁

文章目录 一、分布式锁概念二、使用setnx实现锁三、编写代码测试分布式锁1. 使用Java代码测试分布式锁2. 优化之设置锁的过期时间 四、优化之给lock设置UUID防误删五、使用LUA脚本保证删除的原子性 一、分布式锁概念 随着业务发展的需要&#xff0c;原单机部署的系统被演化成分…

关于分布式锁

先别说了别的&#xff0c;先来一个总结。 synchronized 单机版可以&#xff0c;但是上了分布式就不行了。 nginx 分布式服务单机锁就不行 取消单机锁&#xff0c;上redis分布式锁setnx 注意的问题&#xff1a; 如果只加了锁&#xff0c;没有释放锁&#xff0c;出现异常的话…