1. 程式人生 > 程式設計 >淺談Vue3 Composition API如何替換Vue Mixins

淺談Vue3 Composition API如何替換Vue Mixins

想在你的Vue元件之間共享程式碼?如果你熟悉Vue 2 則可能知道使用mixin,但是新的Composition API 提供了更好的解決方案。

在本文中,我們將研究mixins的缺點,並瞭解Composition API如何克服它們,並使Vue應用程式具有更大的可伸縮性。

回顧Mixins功能

讓我們快速回顧一下mixins模式,因為對於下一部分我們將要講到的內容,請務必將其放在首位。

通常,Vue元件是由一個JavaScript物件定義的,它具有表示我們所需功能的各種屬性——諸如 data,methods,computed 等。

// MyComponent.js
export default {
 data: () => ({
  myDataProperty: null
 }),methods: {
  myMethod () { ... }
 }
 // ...
}

當我們想在元件之間共享相同的屬性時,可以將公共屬性提取到一個單獨的模組中:

// MyMixin.js
export default {
 data: () => ({
  mySharedDataProperty: null
 }),methods: {
  mySharedMethod () { ... }
 }
}

現在,我們可以通過將其分配給 mixin config屬性將其新增到任何使用的元件中。在執行時,Vue會將元件的屬性與任何新增的mixin合併。

// ConsumingComponent.js
import MyMixin from "./MyMixin.js";

export default {
 mixins: [MyMixin],data: () => ({
  myLocalDataProperty: null
 }),methods: {
  myLocalMethod () { ... }
 }
}

對於這個特定的例子,在執行時使用的元件定義應該是這樣的:

export default {
 data: () => ({
  mySharedDataProperty: null
  myLocalDataProperty: null
 }),methods: {
  mySharedMethod () { ... },myLocalMethod () { ... }
 }
}

Mixins被認為“有害”

早在2016年中期,丹·阿布拉莫夫(Dan Abramov)就寫了《mixin被認為是有害的》(mixin Considered Harmful),他在書中辯稱,將mixin用於在React元件中重用邏輯是一種反模式,主張遠離它們。

不幸的是,他提到的關於React mixins的缺點同樣適用於Vue。在瞭解Composition API如何克服這些缺點之前,讓我們熟悉這些缺點。

命名衝突

我們看到了mixin模式如何在執行時合併兩個物件。如果他們兩個都共享同名屬性,會發生什麼?

const mixin = {
 data: () => ({
  myProp: null
 })
}

export default {
 mixins: [mixin],data: () => ({
  // 同名!
  myProp: null
 })
}

這就是合併策略發揮作用的地方。這是一組規則,用於確定當一個元件包含多個具有相同名稱的選項時會發生什麼。

Vue元件的預設(但可以配置)合併策略指示本地選項將覆蓋mixin選項。Vue元件的預設(可選配置)合併策略指示本地選項將覆蓋mixin選項。不過也有例外,例如,如果我們有多個相同型別的生命週期鉤子,這些鉤子將被新增到一個鉤子陣列中,並且所有的鉤子都將被依次呼叫。

儘管我們不應該遇到任何實際的錯誤,但是在跨多個元件和mixin處理命名屬性時,編寫程式碼變得越來越困難。一旦第三方mixin作為帶有自己命名屬性的npm包被新增進來,就會特別困難,因為它們可能會導致衝突。

隱式依賴

mixin和使用它的元件之間沒有層次關係。這意味著元件可以使用mixin中定義的資料屬性(例如mySharedDataProperty),但是mixin也可以使用假定在元件中定義的資料屬性(例如myLocalDataProperty)。這種情況通常是在mixin被用於共享輸入驗證時出現的,mixin可能會期望一個元件有一個輸入值,它將在自己的validate方法中使用。

不過,這可能會引起一些問題。如果我們以後想重構一個元件,改變了mixin需要的變數的名稱,會發生什麼情況呢?我們在看這個元件時,不會發現有什麼問題。linter也不會發現它,我們只會在執行時看到錯誤。

現在想象一個有很多mixin的元件。我們可以重構本地資料屬性嗎?或者它會破壞mixin嗎?我們得手動搜尋才能知道。

從mixins遷移

mixin的替代方案,包括高階元件,utility 方法和其他一些元件組成模式。

mixins的缺點是Composition API背後的主要推動因素之一,讓我們快速瞭解一下它是如何工作的,然後再看它如何克服mixin問題。

快速入門Composition API

Composition API的主要思想是,我們將它們定義為從新的 setup 函式返回的JavaScript變數,而不是將元件的功能(例如state、method、computed等)定義為物件屬性。

以這個經典的Vue 2元件為例,它定義了一個“計數器”功能:

//Counter.vue
export default {
 data: () => ({
  count: 0
 }),methods: {
  increment() {
   this.count++;
  }
 },computed: {
  double () {
   return this.count * 2;
  }
 }
}

下面是使用Composition API定義的完全相同的元件。

// Counter.vue
import { ref,computed } from "vue";

export default {
 setup() {
  const count = ref(0);
  const double = computed(() => count * 2)
  function increment() {
   count.value++;
  }
  return {
   count,double,increment
  }
 }
}

首先會注意到,我們匯入了 ref 函式,該函式允許我們定義一個響應式變數,其作用與 data 變數幾乎相同。計算屬性的情況與此相同。

increment 方法不是被動的,所以它可以被宣告為一個普通的JavaScript函式。注意,我們需要更改子屬性 count 的 value 才能更改響應式變數。這是因為使用 ref 建立的響應式變數必須是物件,以便在傳遞時保持其響應式。

定義完這些功能後,我們將從 setup 函式中將其返回。上面兩個元件之間的功能沒有區別,我們所做的只是使用替代API。

程式碼提取

Composition API的第一個明顯優點是提取邏輯很容易。

讓我們使用Composition API重構上面定義的元件,以使我們定義的功能位於JavaScript模組 useCounter 中(在特性描述前面加上“use”是一種Composition API命名約定。)。

//useCounter.js
import { ref,computed } from "vue";

export default function () {
 const count = ref(0);
 const double = computed(() => count * 2)
 function increment() {
  count.value++;
 }
 return {
  count,increment
 }
}

程式碼重用

要在元件中使用該函式,我們只需將模組匯入元件檔案並呼叫它(注意匯入是一個函式)。這將返回我們定義的變數,隨後我們可以從 setup 函式中返回它們。

// MyComponent.js
import useCounter from "./useCounter.js";

export default {
 setup() {
  const { count,increment } = useCounter();
  return {
   count,increment
  }
 }
}

乍一看,這似乎有點冗長而毫無意義,但讓我們來看看這種模式如何克服了前面討論的mixins問題。

命名衝突解決了
我們之前已經瞭解了mixin如何使用與消費者元件中的名稱相同的屬性,或者甚至更隱蔽地使用了消費者元件使用的其他mixin中的屬性。

這不是Composition API的問題,因為我們需要顯式命名任何狀態或從合成函式返回的方法。

export default {
 setup () {
  const { someVar1,someMethod1 } = useCompFunction1();
  const { someVar2,someMethod2 } = useCompFunction2();
  return {
   someVar1,someMethod1,someVar2,someMethod2
  }
 }
}

命名衝突的解決方式與其他任何JavaScript變數相同。

隱式依賴…解決了!

前面還看到mixin如何使用在消費元件上定義的 data 屬性,這可能會使程式碼變得脆弱,並且很難進行推理。

合成函式(Composition Function)還可以呼叫消費元件中定義的區域性變數。不過,不同之處在於,現在必須將此變數顯式傳遞給合成函式。

import useCompFunction from "./useCompFunction";

export default {
 setup () {
  // 某個區域性值的合成函式需要用到
  const myLocalVal = ref(0);

  // 它必須作為引數顯式地傳遞
  const { ... } = useCompFunction(myLocalVal);
 }
}

總結

mixin模式表面上看起來很安全。然而,通過合併物件來共享程式碼,由於它給程式碼增加了脆弱性,並且掩蓋了推理功能的能力,因此成為一種反模式。

Composition API最聰明的部分是,它允許Vue依靠原生JavaScript中內建的保障措施來共享程式碼,比如將變數傳遞給函式和模組系統。

這是否意味著Composition API在各方面都比Vue的經典API優越?不是的。在大多數情況下,你堅持使用經典API是沒有問題的。但是,如果你打算重用程式碼,Composition API無疑是優越的。

到此這篇關於淺談Vue3 Composition API如何替換Vue Mixins的文章就介紹到這了,更多相關Vue3 Composition 替換Vue Mixins內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!