computed和watch的区别和使用场景

201 阅读11分钟

大家都知道Vue是一个响应式框架,核心特性之一就是数据绑定系统,能够自动追踪数据的变化,并且相应地更新DOM(文档对象模型),从而使得开发者能够更加高效的构建动态用户界面。

那么在初学时我产生了疑问

  • computed和watch在Vue中是有什么必须存在的原因呢?
  • 为什么需要computed和watch两个来用于响应数据变化,computed和watch有什么区别?
  • computed和watch使用场景分别吗是什么样的?
--接下来根据我所知道的知识来回答之前产生的疑问。

一、 computed和watch在Vue中是有什么必须存在的原因呢

  1. Vue尽管能够自动的更新视图,但是当数据处理的复杂性增加时(例:根据数据变化执行复杂的逻辑和优化性能)就需要更精准的数据控制操作,还有变化响应等。
  2. 而且还有一点就是尽管模板内的表达式非常便利,但设计初衷是用于简单运算的。如果在模板中放入太多的逻辑就会让模板过重、难以维护.....

所以基于这些需求,Vue引入了computed和watch。能够让Vue能够适应各种复杂的开发需求。

二、为什么需要computed和watch两个来用于响应数据变化,computed和watch有什么区别?

首先理解computed和watch,然后总结它们有什么区别

computed(计算属性)

  • computed是Vue中一种特殊属性计算结果会被缓存只有当它依赖的响应式数据发生变化时,根据响应式数据的变化自动重新计算值。

computed 关键点:

  • computed属性用于创建派生数据,这些数据是基于响应式依赖自动计算的
    注:"派生数据"(Derived Data)是指基于已有数据通过某种计算或转换得到的新数据)。
    例:
    多个输入字段计算总和。
    根据用户权限动态展示不同的视图。
    购物车应用中根据商品列表计算总价。
  • 它们提供了缓存机制,只有当依赖项变化时,计算属性才会重新计算。
  • computed适合于声明性地描述数据如何从其他数据派生,常用于视图渲染优化。

watch(侦听器)

  • watch允许你指定一个或多个响应式数据,并对这些数据的变化执行自定义的操作。

watch 关键点:

  • watch用于侦听响应式数据的变化,并在变化发生时执行定义的逻辑。
  • 它不具备缓存机制,每次数据变化都会触发回调函数。
  • watch适合于执行复杂的业务逻辑,如异步请求DOM操作或者在数据变化时执行条件性响应
    例:
    表单输入的实时验证。
    用户搜索输入的自动完成或搜索结果的实时更新。
    路由参数的变化导致组件状态的更新。

总结出它们的区别在于 :

功能定位

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

缓存与执行

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

返回值

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

初始执行

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

watch  属性监听 监听属性的变化

computed:计算属性通过属性计算而得来的属性

watch中的函数是不需要调用的

computed内部的函数调用的时候不需要加()

当computed中的函数所依赖的属性如果没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取

watch 一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;

三、computed和watch使用场景分别吗是什么样的?

简洁来说:
computed     

    当一个属性受多个属性影响的时候就需要用到computed

    最典型的例子: 购物车商品结算的时候

watch

    当一条数据影响多条数据的时候就需要用watch

    搜索数据

computed 较适用于以下场景:

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

换个说法就是:

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

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

watch 较适用于以下场景:

  • 当数据变化需要触发复杂的业务逻辑或副作用时。
  • 当你需要在数据变化时执行异步操作,如API请求时。
  • 当需要对数据变化做出条件性响应,如根据用户输入切换不同的视图或状态时。

例:
1.考虑一个具有实时搜索功能的应用,用户在搜索框中输入文本时,应用需要动态更新搜索结果。
2.假设我们有一个表单,用户需要输入用户名,我们希望在用户输入时立即验证用户名的有效性。

--具体场景 使用computed和watch

1.性能优化场景
你正在开发一个性能敏感的Vue应用,其中有一个属性userPreferences,你想要基于这个属性计算出一个theme变量,用于应用不同的样式。这个theme变量在userPreferences变化时才会更新。

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

2.复杂副作用场景
假设用户在应用中更改了他们的主题偏好,除了更新应用的样式外,你还需要保存这个新的主题到数据库,并且可能需要从服务器获取一些与主题相关的数据。

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

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

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

4.异步操作场景
你正在构建一个搜索功能,用户输入查询时,你希望应用能立即显示出与查询匹配的结果。这个搜索过程涉及到一个异步API调用。

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

5.条件渲染场景
你的应用有一个特性,根据当前用户的角色,某些UI元素可能会显示或隐藏。这个显示逻辑依赖于一个currentUser对象中的role属性。

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

6.跨组件通信场景
你正在构建一个复杂的Vue应用,其中有一个父组件和一个子组件。父组件需要监听子组件的状态变化,并在变化时更新自己的状态或执行某些操作。这个监听过程不涉及复杂的计算,但需要确保父组件能够响应子组件的状态。

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

7.初始执行场景
你需要在应用启动时立即执行一个初始化过程,这个过程中你会读取用户的首选项,并根据这些偏好设置应用的状态。这个初始化过程只会在应用启动时执行一次,之后会根据用户的行为动态更新状态。

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

--场景问题升级

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

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

2.动态样式应用
在应用中,你希望某些元素的样式根据当前用户的主题偏好动态变化。这些样式不涉及复杂的计算,但是需要立即应用,以响应用户切换主题的动作。

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

3.父子组件状态同步
你有一个父组件和一个子组件,父组件需要基于自己的状态来决定是否启用子组件的某个功能。与此同时,子组件的行为也可能影响父组件的状态。

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

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

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

5.深层监听对象变化
你有一个嵌套的对象nestedObject,它作为响应式数据存储在Vue实例中。你需要追踪这个对象中所有属性的变化,包括那些在深层嵌套的对象中的属性。

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

6.性能优化与副作用
在应用中,你有一个复杂的计算属性computedProperty,它根据多个响应式数据计算得到。这个计算相对昂贵,但你同时需要在计算结果变化时执行一些副作用,如更新另一个响应式属性。

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

7.异步数据更新
用户在应用中执行了一个动作,比如点击一个按钮,这将触发一个异步操作,如从服务器获取数据。一旦数据获取成功,你需要更新应用的状态,并可能需要基于新数据计算一些派生状态。

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