从同步到异步:Vue 3 的异步更新策略与 `tick` 机制

news/2025/2/27 5:25:21

1. 引言:Vue 3 的异步更新,我们真的了解吗?

在日常开发中,我们都知道 Vue 3 是异步更新的。大多数时候,我们只是简单地使用 refreactivecomputed 等 API,享受着 Vue 的响应式系统带来的便利。然而,当我们在某些场景,忽略“异步”更新的底层逻辑,就会导致和预期不相符的问题。

最近,我在一个项目中遇到了一个关于 computed 的问题,这让我重新审视了 Vue 3 的异步更新机制。下面,我将分享这段经历,希望能帮助大家更好地理解 Vue 3 的异步更新策略。

2. 问题背景:computed 的二次转换与异步更新的冲突

在项目中,我需要对一个响应式数据进行二次转换,以便在模板中使用。为了分离逻辑,我使用了 computed 来实现这个转换。
整个问题涉及到3个文件:

index.vue
Temp.vue
useSearchParam.ts

在index.vue中,使用Temp.vue模块和useSearchParam。然后在index.vue中,通过computed,来处理和searchParam相关的转换逻辑。
代码大致如下:
index.vue

<template>
  <Temp ref="tempRef" :param="computedParam"/>
</template>
<script setup lang="ts">
...
const { searchParam } = useSearchParam(()=>{
  tempRef.value.load();
});
const computedParam = computed(() => {
  return {
    businessCode: `computed businessCode:${searchParam.businessCode}`
  };
});
</script>

Temp.vue 组件中,我通过 props 接收 computedParam,并在 load 方法中打印 businessCode
Temp.vue

<template>
  <span>{{ param.businessCode }}</span>
</template>
<script lang="ts" setup>
interface Props {
  param: any
}
const props = defineProps<Props>();
const load = () => {
  console.log("temp-load-1", props.param.businessCode);
  ...
};
defineExpose({ load });
</script>

useSearchParam.ts 中,我通过异步加载数据并更新 searchParam
useSeachParam.ts

export function useSearchParam(dataLoaded: Function) {
	const searchParam = reactive({});
	onMounted(async () => {
	  const result = await store.businessNames.load({}));
	  searchParam["businessCode"] = first(result)?.code;
	  dataLoaded && dataLoaded();
	});
}

然而,当 businessNames 加载完成后,temp-load-1 打印出来的 businessCodeundefined,而在span中却正常渲染出来了businessCode的值。这让我感到困惑,为什么没有获取到最新的 computedParamcomputed 值?

3. 问题剖析:computed 的惰性求值与异步更新的冲突

通过分析,我发现问题的根源在于 computed 的惰性求值机制。computed 只有在被访问时才会重新计算,而在异步更新中,computed 不会立即重新计算,导致在同步代码中获取到旧的值。

具体来说,当 searchParam.businessCode 被更新时,Vue 会标记 computedParam 为“脏”状态,但不会立即重新计算。只有在 computedParam 被访问时,Vue 才会重新计算并返回最新的值。然而,dataLoaded是一个同步函数(关键之处),当它触发了Temp里面的load方法时,computedParam 还没有被重新计算,导致 props.param.businessCode 仍然是 undefined

4. 解决方案:使用 nextTick 确保 computed 的更新

为了解决这个问题,我调整了 useSearchParam.ts 中的代码,将 dataLoaded 回调函数放入 nextTick 中执行:

onMounted(async () => {
  const result = (await store.businessNames.load({})) as BusinessNameItem[];
  searchParam["businessCode"] = first(result)?.code;
  nextTick(() => {
    dataLoaded && dataLoaded();
  });
});

通过这种方式,dataLoaded 回调函数会在 Vue 的下一个 tick 中执行,此时 searchParam 的更新已经完成,computedParam 也已经重新计算,并返回了最新的值。因此,temp-load-1 和 里面一样,都显示出来了相同的正常值。

5. 深入理解:Vue 3 的 tick 机制

通过这次问题的解决,我深入理解了 Vue 3 的 tick 机制。tick 是 Vue 完成一次响应式数据更新和 DOM 渲染的过程。Vue 会将所有的响应式数据更新和 DOM 更新批量处理,并在下一个事件循环的 tick 中执行。

nextTick 中,Vue 会完成所有响应式数据的更新和 DOM 的渲染,确保回调函数在最新的状态下执行,具体到这个问题中,computedParam已经完成了更新。因此,通过 nextTick,我们可以确保在异步更新后获取到最新的computedParam的 computed 值。

6. 总结:从同步到异步,理解 Vue 3 的异步更新策略

通过这次经历,我们不仅解决了 computed 的异步更新问题,还深入理解了 Vue 3 的 tick 机制。Vue 3 的异步更新策略虽然复杂,但通过合理使用 nextTick,我们可以确保在异步更新后获取到最新的数据。

在日常开发中,我们应该更加关注 Vue 3 的异步更新策略,尤其是在使用 computedwatch 时,确保数据的更新和渲染顺序正确。通过这种方式,我们可以编写出更加高效和可靠的 Vue 3 代码。


http://www.niftyadmin.cn/n/5869502.html

相关文章

【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.1.2典型应用场景:日志分析、实时搜索、推荐系统

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 为什么选择Elasticsearch&#xff1f;——典型应用场景深度解析1. 引言2. 日志分析&#xff1a;海量数据的实时洞察2.1 行业痛点2.2 ES解决方案关键技术实现&#xff1a; 2.…

Linux中的UDP编程接口基本使用

UDP编程接口基本使用 本篇介绍 在前面网络基础部分已经介绍了网络的基本工作模式&#xff0c;有了这些理论基础之后&#xff0c;下面先从UDP编程开始从操作部分深入网络 在本篇中&#xff0c;主要考虑下面的内容&#xff1a; 创建并封装服务端&#xff1a;了解创建服务端的…

Ubuntu本地使用AnythingLLM

1.介绍 AnythingLLM是一个全栈应用程序&#xff0c;由Mintplex Labs Inc.开发&#xff0c;旨在将任何文档、资源或内容片段转换为大语言模型&#xff08;LLM&#xff09;在聊天中可以利用的相关上下文。 2.在ubuntu本地安装 打开终端并运行&#xff1a; curl -fsSL https:/…

每天一个Flutter开发小项目 (5) : 专业Flutter导航与路由 - 构建精美菜谱应用

引言 欢迎再次回到 每天一个Flutter开发小项目 系列博客!在前四篇博客中,我们逐步深入 Flutter 的世界,从基础的计数器、实用的待办事项列表,到联网的天气应用和状态管理的地点收藏应用,相信您已经对 Flutter 开发有了扎实的基础。 随着应用功能的不断扩展,页面间的跳转…

保护密码等敏感信息的几个常用方法

概述 在生产环境&#xff0c;保护数据库账号密码等敏感信息是至关重要的&#xff0c;这些信息不能被所有研发工程师看见&#xff0c;本文介绍几种避免明文存储的常用方法。 方法1&#xff1a; 使用配置中心加密 适用场景&#xff1a;已采用配置中心&#xff08;如Spring Clou…

React Native 0.77正式版发布

此版本发布了几个特性:新的样式功能,例如支持 display: contents、boxSizing、mixBlendMode 和 outline 相关属性,以提供更强大的布局选项;Android 16KB 页面支持,以兼容较新的 Android 设备。我们还在通过将其迁移到 Swift 来现代化社区模板,同时继续支持和维护与 Objec…

48.日常算法

1.面试题 03.06. 动物收容所 题目来源 动物收容所。有家动物收容所只收容狗与猫&#xff0c;且严格遵守“先进先出”的原则。在收养该收容所的动物时&#xff0c;收养人只能收养所有动物中“最老”&#xff08;由其进入收容所的时间长短而定&#xff09;的动物&#xff0c;或…

解锁C# XML编程:从新手到实战高手的蜕变之路

一、引言&#xff1a;XML 在 C# 中的关键地位 在 C# 开发的广袤领域中&#xff0c;XML&#xff08;可扩展标记语言&#xff0c;eXtensible Markup Language&#xff09;宛如一颗璀璨的明星&#xff0c;占据着举足轻重的地位。它以其独特的结构化和自描述特性&#xff0c;成为了…