Vue3,用組合的方式來編寫更好的程式碼(1/5)

前端小智發表於2022-06-30

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

到目前為止,可組合是組織Vue 3應用中業務邏輯的最佳方式。

它們讓你把小塊的邏輯提取到函式中,我們可以輕鬆地重複使用,這樣的程式碼更容易編寫和閱讀。

由於這種編寫Vue程式碼的方式相對較新,你可能想知道在編寫可組合程式碼的最佳做法是什麼。本系列教程將作為一個指南,告訴你如何編寫值得信賴且可靠組合式程式碼。

以下是我們將討論的內容。

  • 如何使用選項物件引數來使組合更有配置性
  • 使用 ref 和 unref 來使我們的論證更加靈活
  • 讓返回值更有用的一個簡單方法
  • 為什麼從介面開始會使我們組合會更強大
  • 如何使用不需要 await 的非同步程式碼--讓你的程式碼更容易理解

首先, 我們先不看什麼是可組合式?

什麼是可組合式?

根據Vue文件,可組合是 "利用Vue Composition API來封裝和重用有狀態邏輯的函式"。

這意味著任何使用響應式的程式碼都可以變成一個可組合的。

下面是一個來自Vue.js文件的useMouse可組合的簡單例子。

import { ref, onMounted, onUnmounted } from 'vue'

export function useMouse() {
  const x = ref(0)
  const y = ref(0)

  function update(event) {
    x.value = event.pageX
    y.value = event.pageY
  }

  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  return { x, y }
}

我們將狀態定義為 refs,然後在滑鼠移動時更新該狀態。通過返回xy refs,我們可以在任何元件(甚至是另一個可組合的元件)中使用它們。

下面是我們如何在一個元件中使用這個可組合的。

<template>
  X: {{ x }} Y: {{ y }}
</template>

<script setup>
  import { useMouse } from './useMouse';
  const { x, y } = useMouse();
</script>

正如你所看到的,使用 useMouse 組合就可以重複使用所有這些邏輯。只需很少的額外程式碼,我們就能在我們的元件中抓取滑鼠座標。

選項物件引數

大多數可組合程式有一個或兩個必要的輸入。然後有一系列的可選引數來幫助配置可組合的工作方式。

當配置你的可組合的時候,你可以傳入一個選項物件,而不是傳入一長串的引數,。

// 使用一個選項物件
const title = useTitle('A new title', { titleTemplate: '>> %s <<' });
// Title is now ">> A new title <<"

// 使用入一長串的引數
const title = useTitle('A new title', '>> %s <<');
// Title is now ">> A new title <<"

將選項作為一個整體物件而不是引數傳入,給我們帶來一些好處。

首先,我們不需要記住引數的正確順序。現在有了TypeScript和編輯器自動完成功能,這已經不是一個問題了,但它仍然有區別。對於一個Javascript物件,鍵的順序並不重要。

第二,程式碼更易讀,因為我們知道這個選項是做什麼的。程式碼即註釋。我們不需要在原始碼中尋找,也不需要依靠我們的IDE來讓我們知道。

第三,以後再新增新的選項就容易多了。這既適用於向可組合本身新增新選項,也適用於在使用可組合時新增選項。

所以,使用一個選項物件會更好。但我們如何實現呢?

以可組合的方式實施

下面是如何在一個可組合的中實現選項物件模式。

export function useMouse(options) {
  const {
    asArray = false,
    throttle = false,
  } = options;

  // ...
};

在這裡,如果引數是必需的,我們可以接受一兩個引數,然後最後一個引數是選項物件。所以在這個例子中,useMouse沒有必要的引數,只有選項物件。

下一步是分解選項物件。通過解構,我們可以訪問所有的值,並明確地為每個可能的選項提供預設值。

現在,我們將看看VueUse中的兩個不同的組合是如何應用該模式的。VueUse是Vue 3的一個開源組合集合,編寫得非常好。它是學習如何編寫可組合程式碼的一個很好的資源

https://vueuse.org/

首先,我們看看useTitle,然後再看看useRefHistory是如何工作的。

useTitle

useTitle是一個相當簡單的組合。它用來更新頁面的標題。

const title = useTitle('Initial Page Title');
// Title: "Initial Page Title"

title.value = 'New Page Title';
// Title: "New Page Title"

它也有幾個選項以獲得額外的靈活性。

可以提供一個 titleTemplate,還可以設定它來觀察(observe)其他指令碼可能做出的任何改變的標題(使用MutationObserver)。

const titleOptions = {
  titleTemplate: '>> %s <<',
  observe: true,
};

下面是使用選項物件的方式:

const title = useTitle('Initial Page Title', {
  titleTemplate: '>> %s <<',
  observe: true,
});
// Title: ">> Initial Page Title <<"

title.value = 'New Page Title';
// Title: ">> New Page Title <<"

當你檢視useTitle的源時,它是這麼做的:

export function useTitle(newTitle, options) {
  const {
    document = defaultDocument,
    observe = false,
    titleTemplate = '%s',
  } = options;
  
  // ...
}

useTitle可組合式有一個必要的引數,然後是一個 options 物件。在這之後,它完全按照這裡描述的模式實現其餘部分。

現在讓我們看看一個稍微複雜的可組合,它也使用這個選項物件模式。

useRefHistory

useRefHistory 更有趣一些。它可以讓你跟蹤對一個 ref 所做的所有改變,可以容易地執行撤銷和重做操作。

// Set up the count ref and track it
const count = ref(0);
const { undo } = useRefHistory(count);

// Increment the count
count.value++;

// Log out the count, undo, and log again
console.log(counter.value); // 1
undo();
console.log(counter.value); // 0

此可組合可採用許多不同的選項

{
  deep: false,
  flush: 'pre',
  capacity: -1,
  clone: false,
  // ...
}

我們可以把選項物件作為第二個引數傳入,以進一步配置這個可組合的行為方式,與我們之前的例子一樣。

const state = ref({});
const { undo, redo } = useRefHistory(state, {
  deep: true,    // 追蹤物件和陣列內部的變化
  capacity: 15,  // 限制我們追蹤的步驟數量
});

如果我們看一下這個原始碼,我們會發現它使用了與useTitle完全相同的物件重構模式。

export function useRefHistory(source, options) {
  const {
    deep = false,
    flush = 'pre',
    eventFilter,
  } = options;
 
  // ...
}

然而,在這個例子中,我們只在開始時從選項物件中抽出幾個值。

這是因為useRefHistory在內部依賴於useManualRefHistory可組合程式。其餘的選項將作為該可組合的選項物件在後面的可組合中傳遞。

// ...

const manualHistory = useManualRefHistory(
  source,
  {
    // Pass along the options object to another composable
    ...options,
    clone: options.clone || deep,
    setSource,
  },
);

// ...

把所有的東西集中起來

本文是我們“編寫更好的組合”系列的第一部分。

我們研究瞭如何將一個選項物件作為引數新增到元件中,從而使元件的可配置性大大增強。例如,你不需要擔心引數的排序,也不需要記住每個引數的作用,而且向一個物件新增更多的選項要比更新傳入的引數容易得多。

但我們並不只是看了這個模式本身。我們還看到了VueUse的組合物 useTitleuseRefHistory 是如何實現這一模式的。他們的方式略有不同,但由於這是一個簡單的模式,你可以做的變化不多。

本系列的下一篇文章將探討我們如何接受Refs和常規Javascript值作為引數。

// 傳遞一個 ref 值,可以工作
const countRef = ref(2);
useCount(countRef);

// 或者只給一個簡單的數字
const countRef = useRef(2);

這增加了靈活性,允許我們在應用程式的更多情況下使用組合。

編輯中可能存在的bug沒法實時知道,事後為了解決這些bug,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

作者:Michael Thiessen 譯者:小智 來源:vuemastery

原文: https://www.vuemastery.com/bl...

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章