[重构倒数第22天] - 减少 watch,改用 computed

前言

该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系列文章,在这边整理了许多我自己使用Vue重构很多网站的经验分享给读者们。

mike vue

我们开发的时候常常会需要监控资料的变化,提到资料的监控很多人第一个反应都会想到使用 watch这个方法来监控资料,然後当资料改变的时候再做些什麽事情,我们可以先来看看以下这个范例。

首先我新增了一个 contentText的资料,然後在它 onMounted去执行 setTimeout让它一秒後改变里面的 value 。

const { createApp, ref, watch, onMounted } = Vue;
const App = {
  setup(){
    const contentText = ref("home")
    
    onMounted(()=> {
      setTimeout(()=> {
        contentText.value = "about"
      }, 1000)
    })
    return {
      contentText
    }
  }
}

然後我会把这个 contentText 当成 props 传下去我的子组件

<div id="app">
  <conetnt-bar :styletype="contentText"></conetnt-bar>
</div>

我们来看一下子组件

app.component('conetnt-bar', {
  props: {
    styletype: {
      type: String,
      default: ''
    }
  },
  setup(props){
    const text = ref("")
    
    const handleType = (styletype) =>{
      if(styletype === 'home'){
        text.value = "首页"
      }
      if(styletype === 'about'){
        text.value = "关於我们"
      }
    }
    
    watch(()=>props.styletype, (newVal)=> {
      handleType(newVal);
    })
    
    onMounted(()=> {
      handleType(props.styletype);
    })
    
    return {
      props,
      text
    }
  },
  template: `
    <h1>{{ text }}: {{props.styletype}}</h1>
  `
})

我们来理解一下这边所做的事情

  1. 首先一开始的时候会我会在 onMounted地方去检查 props 传下来的 styletype 是什麽,然後改变相对应的文字。
  2. 如果今天传下来的 styletype 被更改了,我会再透过 watch去监控 props 的改变,然後一样去判断,然後改变相对应的文字。

codepen范例 : https://codepen.io/MikeCheng1208/pen/OJmdNzO

我们在开发上面很长就会有像是这样子类似的开发方式,需要去监控资料是否有改变,说老实话这个逻辑没有错,也的确可以这样做,但是像是现在看到的这个范例,他其实可以不用到watch,因为在我看过很多这种重构类型的专案,大部分都太滥用 watch 了,其实有一个东西叫做 computed,我稍微跟大家介绍一下 computed

computed 是一个计算属性,设计它的初衷是用於简单运算的,在模板中放入太多的逻辑会让模板过重且难以维护,所以会需要透过computed 来重新处理过那些复杂的资料,官方文件有提到说

computed 属性是基於Vue绑定的资料依赖关系缓存的

这意味者 computed 只在透过Vue绑定的资料发生改变时它们才会重新去执行处理计算,所以今天你的资料只要是Vue绑定的资料,都可以被计算处理过。

我们来看这边改过後的例子:

const { createApp, ref, computed, onMounted } = Vue;

// ------

app.component('conetnt-bar', {
  props: {
    styletype: {
      type: String,
      default: ''
    }
  },
  setup(props){
    
    const text = computed(()=> {
      if(props.styletype === 'home') return "首页"
      if(props.styletype === 'about') return "关於我们"
      return ''
    })
    
    return {
      props,
      text
    }
  },
  template: `
    <h1>{{ text }}: {{props.styletype}}</h1>
  `
})

codepen范例 : https://codepen.io/MikeCheng1208/pen/bGWzwNd

在这边你会看到我拿掉了 ref以及 watch 两个方法,只载入了 computed ,透过 computed 我们可以更加简单的去重组我们的资料,减少不比要的逻辑,只需要透过资料之间的重组,来产生出新的资料,而且只要 computed内的资料没有改变,就不会触发重新 render,这就是 缓存,使用computed的好处。

我们为什麽需要缓存?假设我们有一个性能开销比较大的计算属性 list,它需要遍历一个巨大的数组并做大量的计算。然後我们可能有其他的计算属性依赖於 list。如果没有缓存,我们将不可避免的多次执行 list 的 getter!如果你不希望有缓存,请用 method 来替代。
参考官方文件:https://v3.vuejs.org/guide/computed.html

还有许多例子,例如我们会利用 watch 监听 vue-router,看它的网址有没有被改变,然後去改变画面上的某的资料或是状态,我们在 vue-router 的官方文件上面会看到这样用法的例子

import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'

export default {
  setup() {
    const route = useRoute()
    const activeClass = ref('')

    watch(() => route.params.id, (newId) => {
        activeClass.value = `active-${newId}`
    })
    
    return { activeClass }
  },
}

但是如果使用 computed 就可以改成这样子

import { computed } from 'vue'
import { useRoute } from 'vue-router'

export default {
  setup() {
    const route = useRoute()
    const activeClass = computed(()=> `active-${route.params.id}`)
    return { activeClass }
  },
}

你会发现少了很多的 code,变得简单很多,还有很多开发上面 watch 都可以改成 computed 的例子,现在你了解到了 computed 的美好,今天开始就开始尝试使用 computed 吧~

最後

开发上面虽然是先求有再求好,但是当有多余的时间的时候,可以在回过头来看一下哪边可以来优化的,只要多练习几次,以後就会在开发中越来越精准的使用,基本上这样也可以减少发生问题的机率了。

好啦~今天就到这边啦,有想到其他要补充的我会在打上来,明天见!

Mike Vue

那如果对於Vue3不够熟的话呢?

Ps. 购买的时候请登入或注册该平台的会员,然後再使用下面连结进入网站点击「立即购课」,这样才可以让我获得更多的课程分润,还可以帮助我完成更多丰富的内容给各位。

我有开设了一堂专门针对Vue3从零开始教学的课程,如果你觉得不错的话,可以购买我课程来学习
https://hiskio.com/bundles/9WwPNYRpz?s=tc

那如果对於JS基础不熟的朋友,我也有开设JS的入门课程,可以参考这个课程
https://hiskio.com/bundles/b9Rovqy7z?s=tc

订阅Mike的频道享受精彩的教学与分享

Mike 的 Youtube 频道
Mike的medium
MIke 的官方 line 帐号,好友搜寻 @mike_cheng


<<:  [iT铁人赛Day9]JAVA阵列(下篇)

>>:  Spring Framework X Kotlin Day 4 MVC

调用 Properties.Resources 全域资源档

有时候难免要使用一些资源档 步骤分为 新增 & 使用 新增 在方案总管的专案上右键 选属性 ...

DAY16 - 在 Bitbucket 显示 Jupyter Notebook

前言 今天是铁人赛的第十六天,要来写一下如何在Bitbucket显示 Jupyter Noteboo...

DAY22-JAVA的package

当一个大型程序交由数个不同专员开发时,用到相同的类别名称是很有可能的,当这种情况发生时,为了确保程序...

Day-7 带着童年的好朋友任天堂红白机、重新在 HDMI 电视上发光吧!

写了好几天的事前准备、我想大家应该都腻了。终於、准备到了一定程度、可以进入本文了。这篇文章主要的目的...

Day-17 同步、非同步与事件循环

JavsScripe是一套非同步的、单执行绪(single-threaded)语言,任务与任务之间必...