[重构倒数第21天] - 五种重构Vue2专案的时候最常看到需要被改善的code

前言

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

我常常在重构专案的时候会看到前人写的一些关於 vue 的 code 让人摸不着头绪,以及满头问号的情况,今天我将把一些我常常看到觉得不必要的写法以及可以改善的 code 做个比较,让大家在写 code 的时候可以多多注意不要写出让人满头问号的程序码。

1. 你的 this 与 arrow function

https://ithelp.ithome.com.tw/upload/images/20210910/20125854JVrN3pJNAE.png
这是我在很多专案常见到的 methods 的写法

// option api style from vue-cli
methods: {
  init: function() {
    let that = this;
    axios.get("https://test.api/data").then(function(res){
      that.resVal = res.data
    })
  }
}

这个写法不能说不能 work,只不过不是最理想的写法,首先

  1. 在 Vue cli 里面写 methods 的时候,就可以采用 es6 写法去掉:function() 直接 init()就好。

  2. 使用其他第三方工具的时候,call back function 应该使用 ES6 的箭头函式 ( arrow function ),使用箭头函式就不需要去外面宣告一个 that 塞入this ,因为箭头函示内部是没有 this 的指向,所以会往外部查找,就会直接指向 Vue。

// option api style from vue-cli
methods: {
  init() {
    axios.get("https://test.api/data").then((res)=>{
      this.resVal = res.data
    })
  }
}

2. let 啦!那次不 let !

https://ithelp.ithome.com.tw/upload/images/20210910/20125854Ca3K77T7NF.png
天阿!太多人分不清楚什麽时候应该用 let还是 const,所以乾脆一律 let 到底,我们来看一下什麽东西应该let 什麽应该 const

methods: {
  loginUser (){
    let url = "/api/login";
    let postData = {
      name: this.name,
      password: this.password,
      phone: this.phone,
    };
    axios.post(url, postData).then((res)=> {
		console.log("login success");
    })
  }
}

这是一个很简单的使用 API post 来进行登入的 function,你会看到这边的 url 还有要 post 出去的 data 都是使用let 进行宣告,我们来分析一下,首先 let 除了是以大括号为界,具有scoped的效果,也具有可以修改的特性,你可以随意地修改它里面的 value ,例如下面这种操作都是可以的

let a = 1;
console.log(a);
a = "mike"
console.log(a);

但是我们有些变数是不需要被修改的,例如我们的范例一样,我们的 url 就是一个 API 的路径,它是不会被修改的,所以这边我们就应该用 const来宣告,而不是 let,我们的 postData 其实也是一样的,它是最後将所需要的值给组合起来 post 出去的,所以他也应该用 const

const url = "/api/login";
const postData = {
  name: this.name,
  password: this.password,
  phone: this.phone,
};

关於 let 跟 const 的更多差异我相信网路上已经有很多这类的比较资料,这边我就不再多做赘述。

这边附上 MDN 的文件,还不了解的可以看一下。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#declarations

3. 你的 props 的 type 呢 ?

https://ithelp.ithome.com.tw/upload/images/20210910/20125854LW8yaUrHzU.png
我看过好多人在写 Component 的时候 props 都这样写,直接用一个 Array 包起来这样

<script>
export default {
  props: ["usertype", "handleOpenNav", 'count'],
  ...
}
</script>

但是我们可以看到 Vue 官方的 style guide 上面有明确的讲说这样是你在一开始设计 component 的时候用,当你的资料类型都确定完成後,要改成以下写法。

<script>
export default {
  props: {
    usertype: {
      type: String
    },
    handleOpenNav: {
      type: Function
    },
    count: {
      type: Number
    }
  },
  ...
}
</script>

这样我们就可以去定义我们传入的 props 的类型,也可以一眼就知道这个传入的 props 类型是什麽,即便传错了类型的参数,log 也会报错跟你说参数传入错误了。

props style guide
https://v3.vuejs.org/style-guide/#prop-definitions-essential

然後我最推荐的写法是除了加上 type 以外,还加入了 default 的处理 props 的方式。

<script>
export default {
  props: {
    usertype: {
      type: String,
      default: "default"
    },
    handleOpenNav: {
      type: Function,
      default: ()=> {}
    },
    count: {
      type: Number,
      default: 0
    }
  },
  ...
}
</script>

你可以看到我给了每一个 props 一个 default value,如果今天我没有传入的 props,它就会当成你 default 设定的那个 value 来使用,这样可以避免掉很多如果你没有传入参数的时候,也可以透过这种方式来处理画面上面的状态,让它有预设的 status。

https://v3.vuejs.org/style-guide/#empty-lines-in-component-instance-options-recommended

这边我列几个很容易写错了的 props default 给大家参考

<script>
export default {
  props: {
    handleOpenNav: {
      type: Function,
      default: ()=> {}
    },
    userList: {
      type: Array,
      default: ()=> ([])
    },
    fetchData: {
      type: Object,
      default: ()=> ({})
    },
  },
  ...
}
</script>

最常看到写错的就是 FunctionArrayObject这三个 type,你仔细看 FunctionArray都是需要透过函式的方式去回传,而不是直接定义一个空的 []或是 {},这点要特别注意。

关於 props 定义的部分可以看这份文件
https://v3.vuejs.org/guide/component-props.html#prop-validation

4. Methods 与 Computed 的纠葛

https://ithelp.ithome.com.tw/upload/images/20210910/20125854ATPMjMjc16.png
我们很常会搞不清楚什麽时候应该用 Computed 什麽时候应该用 Methods 来处理资料的回传,我们先来看一下Computed 的部分,在我们前一篇的文章有提到

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

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

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

我们来看以下例子

<script>
export default {
  props: {
    showType: {
      type: String,
      default: 'not_login',
    },
  },
  setup(props) {
    const isShowBtnStatus = () => props.showType === "not_login";
    return { isShowBtnStatus };
  },
};
</script>

<template>
  <a v-if="isShowBtnStatus()">登入</a>
  <a v-if="!isShowBtnStatus()">登出</a>
  <a v-if="!isShowBtnStatus()">观看纪录</a>
</template>

我们可以看到这边 isShowBtnStatus 这个 methods去判断我的 props,然後在 template 的地方去call 这个 methods,让它回传状态,但其实我们应该要改成使用 computed 才对

<script>
import { computed } from "vue";
export default {
  props: {
    showType: {
      type: String,
      default: 'not_login',
    },
  },
  setup(props) {
    const isShowBtnStatus = computed(() => props.showType === "not_login");
    return { isShowBtnStatus };
  },
};
</script>

<template>
  <a v-if="isShowBtnStatus">登入</a>
  <a v-if="!isShowBtnStatus">登出</a>
  <a v-if="!isShowBtnStatus">观看纪录</a>
</template>

透过 computed 的方式可以让资料达到缓存的效果,资料没变就不会重新计算,除非今天你是要传参数进去做计算,才需要选择 methods 来return value.不然的话大部分的计算需求使用 computed 是比较恰当的!

5. Composition Api 跟 Option Api 混用 !?

https://ithelp.ithome.com.tw/upload/images/20210910/201258544FFmeoK06g.png
很多在刚开始升级 Vue3 的朋友会因为还不习惯使用 composition api 而写出以下的 code

import { ref } from 'vue'
export default {
  props: {
    user: {
      type: String,
      required: true
    }
  },
  data () {
    return {
      filters: {}, 
      searchQuery: ''
    }
  },
  setup (props) {
    const repositories = ref([])
    const handleLog = () => {
      console.log("use")
    }
    
    return {
      repositories,
      handleLog
    }
  },
  watch: {
    searchQuery(){ ... }
  },
  mounted () {
    this.handleLog()
  }
}

你会发现这边把 Composition Api 跟 Option Api 给混再一起,变得很奇怪,定义data的地方变成了两个,使用 methods 的时候一下在Option Api 里面要使用 this 但是在 setup 里面又不用,整个变得难以阅读且凌乱,在使用 Composition Api 的时候就可以全部解决这样的问题。

import { ref, reactive, watch, onMounted } from 'vue'
export default {
  props: {
    user: {
      type: String,
      required: true
    }
  },
  setup (props) {
    const repositories = ref([])
    const searchQuery = ref("")
    const filters = reactive({})
    
    const handleLog = () => {
      console.log("use")
    }
    
    watch(searchQuery, (newVal)=> {
      console.log("newVal=>", newVal)
    })
    
    onMounted(()=> {
    	handleLog()
    })
    
    return {
      repositories,
      handleLog
    }
  }
}

你看我把原本 Option Api 的部分全部改成 Composition Api 是不是清爽许多,官方也是建议 Composition Api 跟 Option Api 则一选择就好,不推荐两种写法混用,导致你的 code 看起来很混乱。

更多关於 Composition Api 的内容
https://v3.vuejs.org/guide/composition-api-introduction.html#introduction

好啦!今天就到这边啦~明天见!

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


<<:  Day10 javascript for回圈

>>:  Day 09:「啊~不要碰我!我会变色~」- 变化模式 (Variants)

CISSP统计 - 2021年01月

过去统计数 CISSP Member Counts as of July 1, 2020 ISC2...

Day 29. Hi-Fi Prototype-以 Figma 制作高精度原型 (下)

由於 Figma 的核心是 GUI 设计工具,附带原型制作能力,所以一般来说我们都会使用它来进行高精...

LINE BOT聊天机器人-第二步-建立回声机器人

这次要来建立一个我说甚麽你跟着说的机器人。 你需要从刚刚申请的LINE帐号中拿两个东西跟你的程序码做...

网页图片-30天学会HTML+CSS,制作精美网站

图片在网页里是不可或缺的元素,可以增加网站的丰富度及美感,但是也可能造成网站花太多时间载入,使用者体...