Vue 3 watchEffect:如何用 onInvalidate 优化副作用处理

news2024/11/13 9:42:49

在 Vue3 中,watchEffect 是一个用于在响应式数据变化时自动重新执行的函数。它在创建响应式副作用时特别有用,比如在某些数据变化时更新 DOM、发起网络请求或处理复杂的逻辑。

watchEffect 的 onInvalidate 是一个非常重要的功能,用于处理副作用函数,理解它可以帮助我们在复杂的应用中更好地管理资源,避免内存泄漏和不必要的副作用执行。

1. watchEffect 基本使用

watchEffect 用于自动追踪其内部副作用函数中的响应式数据,当这些数据发生变化时,副作用函数会重新执行。

举个 🌰

import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(() => {
  console.log(`Count is: ${count.value}`);
});

2. onInvalidate 基本使用

onInvalidate 是一个参数,用于处理副作用的取消或清理操作。当在副作用函数中使用了某些资源(如定时器、订阅等),可能需要在副作用函数重新执行之前清理这些资源,以防止内存泄漏或其他问题。

举个 🌰

<template>
  <div>
    <p>当前计数: {{ count }}</p>
    <button @click="count++">增加计数</button>
  </div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    const count = ref(0);
    watchEffect((onInvalidate) => {
      console.log('副作用函数执行');
      const timer = setInterval(() => {
        console.log(`计时器中 count 的值: ${count.value}`);
      }, 1000);
      onInvalidate(() => {
        console.log('清除计时器');
        clearInterval(timer);
      });
    });
    return {
      count,
    };
  },
};
</script>

按道理而言:使用 onInvalidate 清理计时器,每次 count 变化时,watchEffect 会重新执行,在此之前 onInvalidate 会先清理掉之前的计时器,避免重复创建计时器导致内存泄漏。

当我们点击按钮改变 count 值时,watchEffect 重新执行,每秒打印出值,但是 onInvalidate 失效,console.log 没有输出“清楚计时器”,大家可以先分析一下为什么哦?

原因:

watchEffect 的 onInvalidate 在依赖项发生变化时会被触发,关键在于依赖的正确追踪。而上面代码中,count 的变化没有触发 onInvalidate,是因为 watchEffect 没有正确追踪到 count 的依赖。

watchEffect 只能追踪在副作用函数内部使用的响应式数据。如果在 watchEffect 没有直接使用 count.value ,那么它的变化就不会触发副作用函数重新执行,从而不会调用 onInvalidate 清理之前的计时器。

虽然在 setInterval 的回调函数中使用了 count.value,但这并不足以让 watchEffect 追踪到 count 的变化。watchEffect 只会在它同步执行的那一刻,追踪它直接访问的响应式数据。如果响应式数据只是在异步回调(如 setInterval)中访问,它将不会触发 watchEffect 的重新执行。

解决方案:

在 watchEffect 的主逻辑中,直接访问 count.value 即可。

<template>
  <div>
    <p>当前计数: {{ count }}</p>
    <button @click="count++">增加计数</button>
  </div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    const count = ref(0);
    watchEffect((onInvalidate) => {
      // 在函数内直接读取 count.value,确保它被追踪,这一步很重要!!!
      console.log(`副作用函数执行,count 值为: ${count.value}`);
      const timer = setInterval(() => {
        console.log(`计时器中 count 的值: ${count.value}`);
      }, 1000);
      onInvalidate(() => {
        console.log('清除计时器 timer');
        clearInterval(timer);
      });
    });
    return {
      count,
    };
  },
};
</script>

此时控制台输出的结果就是我们预期的!

3. 引入原因

1、清理副作用

在副作用函数中使用 onInvalidate 可以确保在副作用函数重新执行之前,之前的副作用会被正确清理。这样可以避免资源泄漏,例如未清除的定时器或未取消的事件监听器。

2、处理异步操作

对于异步操作(如 API 请求),onInvalidate 可以用于取消未完成的请求。例如,在某个数据变化时,取消之前发出的请求。

3、避免性能问题

在副作用函数中进行清理操作可以避免重复的资源消耗,提升应用性能。例如,在组件卸载时清理定时器或订阅可以避免不必要的计算和内存使用。

4. 注意事项

1、副作用函数的重用

onInvalidate 只在副作用函数重新执行之前调用。如果副作用函数的逻辑是复用的,确保清理操作不会在副作用函数的每次执行中重复触发。

2、异步操作的取消

对于异步操作,确保在 onInvalidate 中正确地取消操作。如果使用 fetch 或其他异步 API,考虑使用 AbortController 进行取消。

3、不必要的清理

避免在 onInvalidate 中做过多的清理操作,确保只处理真正需要的清理逻辑。

举个 🌰

假设有一个网络请求场景,每当数据变化时都会重新发起网络请求,但如果请求未完成时数据再次变化,则会取消之前的请求。在这里,我们只希望 onInvalidate 在新的请求发起之前调用,而不是每次请求逻辑执行时都重复触发清理操作。

<template>
  <div>
    <p>当前ID: {{ id }}</p>
    <button @click="id++">增加 ID</button>
    <p>结果: {{ result }}</p>
  </div>
</template>

<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    const id = ref(1);
    const result = ref('');
    watchEffect((onInvalidate) => {
      console.log(`发起新的请求,ID 为: ${id.value}`);
      // 模拟一个网络请求
      const controller = new AbortController();
      fetch(`https://xxx.xxx.com/posts/${id.value}`, { signal: controller.signal })
        .then((response) => response.json())
        .then((data) => {
          console.log('请求成功:', data);
          result.value = data.title;
        })
        .catch((error) => {
          if (error.name === 'AbortError') {
            console.log('请求被取消');
          } else {
            console.error('请求失败:', error);
          }
        });
      // 只在发起新请求之前,取消前一次的请求
      onInvalidate(() => {
        console.log('清理函数执行,取消之前的请求');
        controller.abort();
      });
    });
    return {
      id,
      result,
    };
  },
};
</script>

初次加载时:

正常点击展示:

当按钮点击过快时:

总结

onInvalidate 是 watchEffect 中用于清理副作用函数的有力工具。它可以帮助开发者在副作用函数重新执行之前清理掉不需要的资源或取消正在进行的操作,从而提高应用的性能和稳定性。

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

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

相关文章

新闻资讯类APP流量变现技巧——提升广告变现收益

新闻资讯类APP拥有庞大的用户基础&#xff0c;始终拥有较强的广告变现能力&#xff0c;如何在激烈的行业竞争中凸显媒体的优势&#xff0c;进而吸引更多的广告主&#xff1f;优化核心场景广告样式的同时&#xff0c;挖掘更多的广告场景样式&#xff1f;如何把握好广告变现和用户…

“Interface 和 Type 区别”深度解析

“Interface 和 Type 区别”深度解析 文章目录 一、Interface 和 Type 是什么二、如何使用 Interface 和 Type1. 定义 Interface2. 定义 Type3. 使用 Interface 和 Type4. 区别与联系 三、Interface 和 Type 二者有哪些区别&#xff0c;分别在哪些场景使用1. 区别2. 场景 四、扩…

将Ruoyi框架系统的Swagger接口文档页面优化为knife4j风格

将Swagger文档原来的页面效果改成比较好看的knife4j风格文档页面 优化前&#xff1a; 请求地址&#xff1a;http://localhost:端口号/swagger-ui/index.html 优化后&#xff1a; 请求地址&#xff1a;http://localhost:端口号/doc.html#/home 修改步骤&#xff1a; 1.引入依…

CPU调度算法之优先级调度

点击下载《CPU调度算法之优先级调度》 摘要 CPU的优先级调度算法是一种通过为不同任务分配优先级来决定执行顺序的调度策略。这种算法使得系统能够优先处理那些被认为更重要或紧急的任务&#xff0c;从而提高整体效率和响应速度。然而&#xff0c;优先级调度也可能带来一些问…

快速求和

请编写程序&#xff0c;输入整数 n&#xff0c;快速计算&#xff1a; 输入格式 n 输出格式 s 要求&#xff1a;输出 6 位小数&#xff0c;末位四舍五入。 代码如下&#xff1a; #include<stdio.h> int main(){int n;double s;scanf("%d",&n);s1.0-1.0/(n1…

DeepACO:用于组合优化的神经增强蚂蚁系统

文章目录 Abstract1 Introduction2 Related work2.1 神经组合优化2.2 蚁群优化3 蚁群优化初探4 Methodology4.1 参数化启发式空间4.2 局部搜索与局部神经引导扰动交织4.3 训练启发式学习器4.4 更好的探索4.4.1 多头解码器4.4.2 Top-k熵损失4.4.3 模仿损失5 实验5.1 实验设置5.2…

DWS=管理员用户创建

管理员用户简介 管理员也称作系统管理员&#xff0c;是指具有SYSADMIN属性的帐户。 非三权分立模式下&#xff0c;拥有系统的最高权限&#xff0c;能够执行所有的操作。系统管理员具有与对象所有者相同的权限。管理员用户创建 su - omm source /opt/huawei/Bigdata/mppdb/.mpp…

【数据结构-二维前缀最小值】力扣3148. 矩阵中的最大得分

给你一个由 正整数 组成、大小为 m x n 的矩阵 grid。你可以从矩阵中的任一单元格移动到另一个位于正下方或正右侧的任意单元格&#xff08;不必相邻&#xff09;。从值为 c1 的单元格移动到值为 c2 的单元格的得分为 c2 - c1 。 你可以从 任一 单元格开始&#xff0c;并且必须…

2024年汉字小达人校内选拔的常见问题和解答

广受上海市小学生们关注的2024年第十一届汉字小达人的时间已经确定了&#xff0c;参赛的孩子们已经开始紧锣密鼓的准备中。 如昨天分析的2024年汉字小达人的赛程&#xff0c;即日起到10月20日是学校自行选拔的时间节点。9月25-30日是区级自由报名集中参赛的日子。两个日子有一…

中秋佳节,如何挑选实用有意义的礼物?精选中秋节最佳送礼清单!

当秋风送爽&#xff0c;丹桂飘香&#xff0c;我们即将迎来一年一度的中秋佳节。在这个充满温情与团圆的节日里&#xff0c;赠送礼物成为了表达我们对家人、朋友以及同事的关怀与祝福的重要方式。然而&#xff0c;面对琳琅满目的商品&#xff0c;如何挑选出既实用又有意义的礼物…

《现代食品》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问&#xff1a;《现代食品》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《现代食品》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a; 中粮工程科技有限公司 主办单位…

韩国汽车工业的绿色革命:古瑞瓦特光伏逆变器助力能源转型与可持续发展

韩国汽车工业的绿色革命&#xff1a;古瑞瓦特光伏逆变器助力能源转型与可持续发展 汉江奇迹 带来韩国的工业化和现代化 能源的可持续供给 逐步成为韩国工业发展的关键议题为此&#xff0c;韩国颁布了「国家能源基本计划」 推动再生能源发展 预计到2030年新能源电力占总电力的20…

CCS10导入CCS3.3工程

选择工程 下一步 下一步 下一步 下一步 去掉XDAIS 下一步 下一步编译

QT 对话框 仿文本编辑器

对话框通常是一个顶层窗口&#xff0c;出现在程序最上层&#xff0c;用于实现短期任务或者简洁的用户交互 一、消息对话框&#xff08;QMessageBox&#xff09; 1、QMessageBox类成员函数实现 1&#xff09;实例化 QMessageBox类 对象 2&#xff09;设置对象属性 3&#x…

【Linux】解锁Shell脚本编写秘籍,编程高手之路等你开启

目录 1. 打印命令行提示符2. 获取用户输入的命令行字符串3. 对命令行字符串进行解析(分割&#xff09;4. 处理内建命令4.1. 内建命令</h3>4.2. 外部命令4.3. cd4.5. export4.6. echo 5. 执行命令5.1. 创建子进程进行程序替换 6. 重定向</h2>7. 总代码 1. 打印命令行…

[000-01-002].第03节:Git基础命令

我的博客大纲 我的GIT学习大纲 1、Git的常用命令 2、Git操作步骤&#xff1a; 2.1.操作Git第一步&#xff1a;设置全局的用户签名 1.设置用户名&#xff1a; 格式&#xff1a;git config --global user.name 用户名命令&#xff1a;git config --global user.name root 2.设置…

【开源免费】基于SpringBoot+Vue.JS在线旅游网站(JAVA毕业设计)

本文项目编号 T 025 &#xff0c;文末自助获取源码 \color{red}{T025&#xff0c;文末自助获取源码} T025&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

【网络安全】漏洞挖掘:文件上传实现Webshell

未经许可,不得转载。 文章目录 正文正文 提交文件功能点,显示只能上传png、jpg、pdf文件 上传一个正常的图片,请求响应如下: 可以看到,该文件被上传到redacted.com,这为后面实现Webshell提供了前提。 接着,我上传webshell.php文件,文件内容为payload,拦截请求包,将…

逆变器的防孤岛测试性能评估

逆变器是太阳能发电系统中的关键设备&#xff0c;它将太阳能电池板产生的直流电转换为交流电&#xff0c;供电网或负载使用。在并网运行的太阳能发电系统中&#xff0c;如果电网出现故障&#xff0c;导致与电网断开连接&#xff0c;但逆变器仍然继续向电网供电&#xff0c;这种…

VBA CSV数据拆分

1. Range.TextToColumns函数 Option ExplicitSub txt2Col()ActiveSheet.Range("A2").CopyActiveSheet.PasteSelection.TextToColumns DataType:xlDelimited, _ConsecutiveDelimiter:True, Comma:True End Sub 2. 效果 执行前 cccccc 执行后效果​ cccc 3. 参照 更…