分析 Vue 3 页面数据加载延迟问题

1. 问题描述

在 Vue 3 的项目中,当我们使用响应式数据(如 ref 或 computed)来管理页面状态时,可能会遇到由于接口数据加载延迟,导致页面初始渲染时数据尚未获取完成的问题。这会导致页面在数据未更新的情况下提前渲染出来,从而产生显示错误或不完整的内容。

针对此问题简单分析下原因和解决方法。

1、Vue 响应式系统的工作机制

Vue 3 的响应式系统基于 Proxy 实现,通过 reactive、ref 或 computed 等 API 来响应数据的变化。当数据变化时,Vue 会自动重新渲染与这些数据绑定的 DOM 元素。但是,如果数据在初始渲染时为空或未加载,Vue 会将页面渲染为初始状态,直到数据加载完毕并触发响应式更新。

🌰

假设存在一个 ref 类型的响应式数据 data,在组件加载时该数据为空,且需要从接口获取数据。

import { defineComponent, ref, onMounted } from 'vue';export default defineComponent(() => {const data = ref(''); // 初始值为空onMounted(async () => {// 模拟延迟获取接口数据await new Promise((resolve) => setTimeout(resolve, 3000));data.value = '已加载的数据'; // 设置接口返回的数据});return () => (<div><p>{data.value ? data.value : '加载中...'}</p></div>);
});

效果:组件渲染时,data.value 为 null,所以会展示 加载中...,3秒之后,数据才被加载,页面才会更新。

2、异步加载时的页面闪烁与内容不一致

接口请求需要时间,页面初始渲染会先使用默认数据或空值进行渲染。数据加载完成后,页面可能会发生更新,导致用户看到的内容短暂不一致或发生闪烁。

2. 解决方法

1、手动触发页面更新

如果响应式数据未触发渲染,可以尝试使用 nextTick 或通过直接重新赋值触发更新。

🌰

import { defineComponent, ref, nextTick } from 'vue';
export default defineComponent(() => {const message = ref<string | null>(null);const updateMessage = async () => {setTimeout(() => {message.value = 'Hello, Vue!';nextTick(() => {console.log('视图已更新');});}, 1000);};updateMessage();return () => (<div><p>{message.value || '加载中...'}</p></div>);
});

2、使用占位符避免初次渲染闪烁

在初次加载数据前,渲染占位符或骨架屏,确保用户体验。

🌰

import { defineComponent, ref } from 'vue';
export default defineComponent(() => {const loading = ref(true);const data = ref<string | null>(null);setTimeout(() => {data.value = '接口数据加载完成';loading.value = false;}, 2000);return () => (<div>{loading.value ? (<p>加载中...</p>) : (<p>数据:{data.value}</p>)}</div>);
});

3、异步逻辑补充响应式支持

在异步接口中获取数据后,直接调用 Vue 提供的响应式 API 来强制触发更新。

🌰

import { defineComponent, reactive } from 'vue';
export default defineComponent(() => {const state = reactive({list: [] as string[],});const fetchList = async () => {setTimeout(() => {state.list = ['Item 1', 'Item 2', 'Item 3']; // 确保重新赋值触发响应式}, 1000);};fetchList();return () => (<div><ul>{state.list.length > 0 ? state.list.map((item) => <li>{item}</li>) : '加载中...'}</ul></div>);
});

4、使用 watch 监听数据变化并在更新时执行额外的逻辑。

🌰

import { defineComponent, ref, watch } from 'vue';
export default defineComponent(() => {const data = ref<string | null>(null);watch(data, (newVal) => {console.log('数据已更新:', newVal);});setTimeout(() => {data.value = 'Hello, World!';}, 1000);return () => (<div><p>{data.value || '加载中...'}</p></div>);
});

关键点:

1、确保使用响应式对象或变量,并在赋值时考虑 Vue 响应式系统的特点。

2、如果页面更新异常,可使用 nextTick 或 watch 来确保触发渲染。

3、提前处理数据加载占位,优化用户体验。

3. 新的疑惑

可能会出现一个困惑:

为什么使用 ref 的响应式数据在页面渲染后获取后,不直接更新页面,而必须放在 watch 里面呢?

ref 的响应式数据本身是具有更新页面的能力的,但如果在页面渲染后会发现数据更新未触发视图变化,可能是由于以下几个原因导致的:

1、页面未绑定响应式数据

如果在模板或渲染函数中,数据未绑定到 DOM 或组件中,Vue 的响应式系统就不会知道该数据的变化需要触发视图更新。

🌰

import { defineComponent, ref } from 'vue';
export default defineComponent(() => {const data = ref<string | null>(null);setTimeout(() => {data.value = '新数据'; // 更新数据}, 2000);return () => (<div>{/* 没有直接使用 data.value */}<p>数据加载完成!</p></div>);
});

示例中,虽然 data.value 被更新了,但它并未绑定到页面上,因此页面没有感知到需要重新渲染。为了解决这个问题,需要确保将数据绑定到视图中:

import { defineComponent, ref } from 'vue';
export default defineComponent(() => {const data = ref<string | null>(null);setTimeout(() => {data.value = '新数据'; // 更新数据}, 2000);return () => (<div><p>{data.value || '加载中...'}</p></div>);
});

2、数据赋值操作不当

当从接口获取数据后,不正确的赋值操作,也可以造成响应式数据未更新导致的。

3、为什么放到 watch 中能解决?

watch 的作用是监听响应式数据的变化并执行相应的副作用逻辑。即使数据更新没有直接绑定到视图,watch 可以保证代码逻辑在数据变化时被触发。

🌰

import { defineComponent, ref, watch } from 'vue';
export default defineComponent(() => {const data = ref<string | null>(null);setTimeout(() => {data.value = 'Hello, Vue!';}, 2000);// 监听数据变化并更新额外逻辑watch(data, (newVal) => {console.log('数据更新为:', newVal);});return () => (<div><p>{data.value || '加载中...'}</p></div>);
});

原因:watch 主动监听数据变化,无论视图是否绑定响应式数据,watch 都会响应数据变化并执行逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/20100.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp 自定义加载组件,全屏加载,局部加载 (微信小程序)

效果图 全屏加载 页面加载使用 局部加载 列表加载里面使用 使用gif html <template><view><view class"" v-if"typeFullScreen"><view class"loading" v-if"show"><view class""><i…

Mac 修改默认jdk版本

当前会话生效 这里演示将 Java 17 版本降低到 Java 8 查看已安装的 Java 版本&#xff1a; 在终端&#xff08;Terminal&#xff09;中运行以下命令&#xff0c;查看已安装的 Java 版本列表 /usr/libexec/java_home -V设置默认 Java 版本&#xff1a; 找到 Java 8 的安装路…

动态规划-最长公共子序列

题目 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长公共子序列的长度。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff08;也可以不删除任何字符&#xff0…

nvm安装node遇到的若干问题(vscode找不到npm文件、环境变量配置混乱、npm安装包到D盘)

问题一&#xff1a;安装完nvm后需要做哪些环境变量的配置&#xff1f; 1.打开nvm文件夹下的setting文件&#xff0c;设置nvm路径和安装node路径&#xff0c;并添加镜像。 root: D:\software\nvm-node\nvm path: D:\software\nvm-node\nodejs node_mirror: https://npmmirror.c…

Zookeeper的简单使用Centos环境下

目录 前言 一、ZOokeeper是什么&#xff1f; 二、安装Zookeeper 1.进入官网下载 2.解压到服务器 3.配置文件 三.使用Zookeeper 3.1启动相关指令 3.2其他指令 3.3ACL权限 总结 前言 记录下安装zookeeper的一次经历 一、ZOokeeper是什么&#xff1f; ZooKeeper是一…

疫情中的图书馆管理:Spring Boot系统设计

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了疫情下图书馆管理系统的开发全过程。通过分析疫情下图书馆管理系统管理的不足&#xff0c;创建了一个计算机管理疫情下图书馆管理系统的方案。文章介绍了疫情下图…

Excel数据动态获取与映射

处理代码 动态映射 动态读取 excel 中的数据&#xff0c;并通过 json 配置 指定对应列的值映射到模板中的什么字段上 private void GetFreightFeeByExcel(string filePath) {// 文件名需要以快递公司命名 便于映射查询string fileName Path.GetFileNameWithoutExtension(fi…

网络(TCP)

目录 TCP socket API 详解 bind(): 我们的程序中对myaddr参数是这样初始化的: listen(): accept(): 理解accecpt的返回值: 饭店拉客例子 connect tcp服务器和udp类似的部分代码 把套接字设置为监听状态&#xff08;listen&#xff09; 测试 查看端口号和IP地址&…

了解鱼叉式网络钓鱼攻击的社会工程学元素

一提到网络攻击&#xff0c;你可能会想象一个老练的黑客躲在类似《黑客帝国》的屏幕后面&#xff0c;利用自己的技术实力积极入侵网络。然而&#xff0c;许多攻击的现实情况远比这平凡得多。 一封带有“未送达”等无害主题的简单电子邮件被放在员工的垃圾邮件文件夹中。他们心…

TS流详解

目录 TS流结构 PSI 节目关联表&#xff08;PAT Program Association Table&#xff09; 条件接收表&#xff08;CAT Conditional Access Table&#xff09; 节目映射表&#xff08;PMT Program Map Table&#xff09; 网络信息表&#xff08;NIT Nerwork Information Tabl…

【图像处理识别】数据集合集!

本文将为您介绍经典、热门的数据集&#xff0c;希望对您在选择适合的数据集时有所帮助。 1 CNN-ImageProc-Robotics 机器人 更新时间&#xff1a;2024-07-29 访问地址: GitHub 描述&#xff1a; 通过 CNN 和图像处理进行机器人对象识别项目侧重于集成最先进的深度学习技术和…

C语言--分支循环编程题目

第一道题目&#xff1a; #include <stdio.h>int main() {//分析&#xff1a;//1.连续读取int a 0;int b 0;int c 0;while (scanf("%d %d %d\n", &a, &b, &c) ! EOF){//2.对三角形的判断//a b c 等边三角形 其中两个相等 等腰三角形 其余情…

Windows系统使用全功能的跨平台开源音乐服务器Navidrome搭建在线音乐库

文章目录 前言1. 安装Docker2. Docker镜像源添加方法3. 创建并启动Navidrome容器4. 公网远程访问本地Navidrome4.1 内网穿透工具安装4.2 创建远程连接公网地址4.3 使用固定公网地址远程访问 前言 在数字时代&#xff0c;拥有一个个性化、便捷的音乐库成为了许多人的需求。本文…

监控易DEMO功能深度解析:运维行业的智能化转型新助力

在数字化转型的浪潮中&#xff0c;运维行业正面临着前所未有的变革与挑战。为了应对日益复杂的IT架构和不断提升的运维需求&#xff0c;监控易的集中式跨平台一体化监控软件不断升级优化&#xff0c;以适应新的运维环境。本文将对监控易DEMO的功能进行深度解析&#xff0c;探讨…

ElasticSearch学习篇17_《检索技术核心20讲》最邻近检索-局部敏感哈希、乘积量化PQ思路

目录 场景在搜索引擎和推荐引擎中&#xff0c;对相似文章去重是一个非常重要的环节&#xff0c;另外是拍照识花、摇一摇搜歌等场景都可以使用它快速检索。 基于敏感性哈希的检索更擅长处理字面上的相似而不是语义上的相似。 向量空间模型ANN检索加速思路 局部敏感哈希编码 随…

SpringBoot MySQL的增删改查

创建数据库和表 安装MySQL&#xff1a;https://blog.csdn.net/qq_59636442/article/details/141926105 通过Navicat 创建数据库test 创建表student后随便添加一条数据 CREATE TABLE student (id int NOT NULL AUTO_INCREMENT,name varchar(255) DEFAULT NULL,email varchar(2…

23种设计模式-备忘录(Memento)设计模式

文章目录 一.什么是备忘录设计模式&#xff1f;二.备忘录模式的特点三.备忘录模式的结构四.备忘录模式的优缺点五.备忘录模式的 C 实现六.备忘录模式的 Java 实现七.总结 类图&#xff1a; 备忘录设计模式类图 一.什么是备忘录设计模式&#xff1f; 备忘录设计模式&#xff08…

如何删除pdf里的任意一页?删除PDF里任意一页的几种方法

如何删除pdf里的任意一页&#xff1f;尽管PDF文件具有许多优点&#xff0c;如跨平台兼容性和格式保真性&#xff0c;但在编辑和修改方面&#xff0c;它与像Word或Excel这类文档格式不同&#xff0c;通常不能像其他文档那样轻松进行直接的内容删除或修改。这让很多人以为&#x…

css3新特性(二十六课)

1、css3盒子模型 box - sizing: content - box&#xff1b; 是 CSS 中用于定义盒模型宽度和高度计算方式的一个属性值。在这种盒模型下&#xff0c;元素的宽度和高度&#xff08;width和height属性&#xff09;仅包括内容区域&#xff08;content&#xff09;的大小&#xff…

Centos7安装Jenkins脚本一键部署

公司原先Jenkins二进制安装&#xff0c;自己闲来无事在测试主机优化了一下&#xff0c;一键部署&#xff0c;jenkins2.426版本jdk11版本 #!/bin/bashjenkins_file"jenkins-2.426.3-1.1.noarch.rpm"# 更新软件包列表 echo "更新软件包列表..." sudo yum up…