Vue3页面数据加载延迟的问题分析和解决方法

 更新时间:2024年11月20日 10:12:15   作者:代码里的小猫咪  
在 Vue 3 的项目中,当我们使用响应式数据(如 ref 或 computed)来管理页面状态时,可能会遇到由于接口数据加载延迟,导致页面初始渲染时数据尚未获取完成的问题,本文针对此问题简单分析了原因和解决方法,需要的朋友可以参考下

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 都会响应数据变化并执行逻辑。

以上就是Vue3页面数据加载延迟的问题分析和解决方法的详细内容,更多关于Vue3页面数据加载延迟的资料请关注脚本之家其它相关文章!

相关文章

  • element滚动条组件el-scrollbar的使用详解

    element滚动条组件el-scrollbar的使用详解

    本文主要介绍了element滚动条组件el-scrollbar的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • vue-router定义元信息meta操作

    vue-router定义元信息meta操作

    这篇文章主要介绍了vue-router定义元信息meta操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • vue父组件向子组件动态传值的两种方法

    vue父组件向子组件动态传值的两种方法

    这篇文章主要介绍了vue父组件向子组件动态传值的两种方法 ,需要的朋友可以参考下
    2017-11-11
  • vue3中关于i18n字符串转义问题

    vue3中关于i18n字符串转义问题

    这篇文章主要介绍了vue3中关于i18n字符串转义问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • 详解在vue中如何实现屏幕录制与直播推流功能

    详解在vue中如何实现屏幕录制与直播推流功能

    屏幕录制和直播推流是现代Web应用中常用的功能,Vue作为一种流行的JavaScript框架,提供了一些工具和库,可以方便地实现屏幕录制和直播推流功能,本文将介绍如何在Vue中进行屏幕录制和直播推流,需要的朋友可以参考下
    2024-01-01
  • Vue props传入function时的this指向问题解读

    Vue props传入function时的this指向问题解读

    这篇文章主要介绍了Vue props传入function时的this指向问题解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Vue.set()和this.$set()使用和区别

    Vue.set()和this.$set()使用和区别

    我们发现Vue.set()和this.$set()这两个api的实现原理基本一模一样,那么Vue.set()和this.$set()的区别是什么,本文详细的介绍一下,感兴趣的可以了解一下
    2021-06-06
  • VUE安装nrm管理多个npm源的方法示例

    VUE安装nrm管理多个npm源的方法示例

    nrm是一个npm源管理器,允许快速切换不同npm源,提高包管理效率,下面就来介绍一下VUE安装nrm管理多个npm源的方法示例,感兴趣的可以了解一下
    2025-01-01
  • vue3使用vueup/vue-quill富文本、并限制输入字数的方法处理

    vue3使用vueup/vue-quill富文本、并限制输入字数的方法处理

    这篇文章主要介绍了vue3使用vueup/vue-quill富文本、并限制输入字数,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • Vue 电商后台管理项目阶段性总结(推荐)

    Vue 电商后台管理项目阶段性总结(推荐)

    这篇文章主要介绍了Vue 电商后台管理项目阶段性总结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08

最新评论