1. 程式人生 > 實用技巧 >vue-next 函式式 api

vue-next 函式式 api

寫在前面

在分享vue-next各個子模組的實現之前,我覺的有必要比較全面的整理下vue-next中提出的函式式api,瞭解這些的話,無論是對於原始碼的閱讀,還是當正式版釋出時開始學習,應該都會有起到一定的輔助作用。

類似的東西在網上有很多,只是會比較零碎,同時有些也相對過時了,當然當前整理的這些也有可能會過時,畢竟程式碼還處於pre-alpha的階段,但其中的設計思想應該是不會改變了。

setup

setup會作為編寫元件業務邏輯的主戰場,各種hook型別的方法均需要在setup這個作用域下呼叫,直接來看RFC中的例子:

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const
state = reactive({ count: 0, double: computed(() => state.count \* 2) }) function increment() { state.count++ } return { state, increment } } } </script>

其程式碼結構看起來和vue2基本保持一致,不過有以下幾點需要注意:

  • setup本身的呼叫時機,從目前的原始碼來看,介於beforeCreate和created這兩個生命週期之間,言外之意,就是你無法在這裡使用this指向當前元件例項
  • 對於state的宣告,我們使用reactive這個api來構造,對於computed state的宣告,使用computed,兩者本質上均是Proxy物件
  • 對於元件方法的宣告,我們直接通過宣告普通函式的方式進行宣告即可,對於state的變更,直接通過閉包使用reactive返回的Proxy物件即可
  • setup的返回值被稱作render context,顧名思義,就是模板中可以訪問到的各種資料和方法的上下文物件,我在之前的文章中曾提及,模板在解析資料時,會優先考慮從data物件取值,之後就是這個render context了
  • 除了返回render context,還可以返回模板渲染函式,對,就是那個h(...),這種形式對應的情況是,當我們沒有宣告template屬性時

在 vue-next 中,我們直接從vue匯入reactive、computed以及其他的api即可,如果在vue2版本上,我們還可以通過使用composition-api這個plugin來使用這些api。

state

宣告 state 主要有以下幾種形式。

基礎型別

基礎型別可以通過ref這個api來宣告,如下:


import { ref } from "vue";

export default {
setup() {
  const count = ref(0);
  
  function inc() {
    count.value++;
  }
  
  return { count, inc };
}
};

之所以要通過ref,是因為js中的基礎型別傳值不是引用傳值,因此vue-next內部會自動將它封裝為一個ref物件,其值指向原始值。當然,ref指向引用型別也是沒有問題的,其value指向引用型別變數的引用。

引用型別

引用型別除了可以使用ref來宣告,也可以直接使用reactive,如下:

import { reactive } from "vue";

export default {
  setup() {
    const state = reactive({
        count: 0
    });
    
    function inc() {
      state.count++;
    }
    
    return { state, inc };
    // 或者通過 toRefs 方法
    // return { ...toRefs(state), inc };
  }
};

這裡使用toRefs的原因主要是因為,如果是 reactive 產生的物件,由於我們要只是儲存對於該 Proxy 物件的引用,我們無法使用解構來將它flat,而toRefs會將每一個屬性在內部包裹為一個ref物件。

props

對於prop可以通過如下程式碼宣告及使用:

export default {
  props: {
    count: Number
  },
  setup(props) {
    watch(() => {
      console.log(\`count is: \` + props.count)
    })
  }
}

這裡可以發現其實和vue2中宣告的方式基本一樣,但值得注意的是,在vue-next中,props的型別宣告不是必須的,如果你使用typescript,完全可以改寫為如下的版本:

interface PropTypesI {
   count: number
}

export default {
  setup(props: PropTypesI) {
    watch(() => {
      console.log(\`count is: \` + props.count)
    })
  }
}

除此之外,還可以直接通過watch方法來觀察某個prop的變動,這是為什麼呢?答案非常簡單,就是props本身在原始碼中,也是一個被reactive包裹後的物件,因此它具有響應性,所以在watch方法中的回撥函式會自動收集依賴,之後當count變動時,會自動呼叫這些回撥邏輯。

context

在setup那一小節中,我們知道,setup在呼叫時,元件例項還未建立,那意味著我們無法使用this訪問當前例項,那我想通過this在vue2中訪問一些內建屬性,怎麼辦?比如attrs或者emit。我們可以通過setup的第二個引數:

setup(props, context) {
  do anything...
}

這個context物件也是一個Proxy物件,當我們通過context.attrs訪問其屬性時,本質上代理物件會將訪問指向元件的內部例項(即之間文章中提及的componentInternalInstance)。

生命週期

每一個vue2中的元件生命週期函式,當前都對應一個生命週期hook,比如:

import { onMounted, onUpdated, onUnmounted } from "vue";

setup() {
  onMounted(() => { ... });
  onUpdated(() => { ... });
  onUnmounted(() => { ... });
}

這裡值得注意的一點在於,對於beforeCreate和created生命週期,雖然有響應的hook,但是我覺的沒有必要單獨使用了,因為這些邏輯程式碼大部分是一些初始化邏輯的程式碼,直接寫在setup方法中即可。

資源搜尋網站大全 http://www.szhdn.com

如何複用程式碼

在這個基礎上,複用程式碼的方式也不再像vue2中的那樣,通過mixin或者HOC來達到複用程式碼的目的,這裡稍微說一下,這些複用程式碼方式中比較顯著的缺點有:

  • 隱藏了資料來源,主要體現在mixin中
  • 會犧牲一些效能,主要體現在HOC中
  • 可能會遇到命名衝突問題,主要體現在mixin中

在vue-next中,複用程式碼的邏輯本質上是利用這些hook來拆分業務邏輯與狀態,如果你比較熟悉react hooks的話,應該很快就能明白我指的是什麼意思。如果我們將邏輯都寫在setup方法中,很快程式碼就會變得難以維護,在這方面,我們可以將一些耦合在一起的程式碼抽離出來,同時以use字首命名,宣告一個自定義的hook,如下:

export default {
  setup() {
    const data = useSearch()
    const { sortedData, sort } = useSorting(data)
    return { data, sortedData, sort }
  }
}

function useSearch() { 
    ...fetch data
}

function useSort(data) { 
    ...sort data
}

除了以inline的方式來宣告,還可以將這些自定義的hook宣告在單獨的檔案中,直接通過import匯入即可,比如:

import useSearch from '@hooks/search'
import useSort from '@hooks/sort'a

與react hooks對比

vue-next在這方面借鑑了react hooks的設計思想,但是從實現層來講,它們是不一樣的,主要有以下幾點:

  • vue-next不依賴於其呼叫順序,而react依賴
  • vue-next提供了生命週期方法,而react刻意模糊生命週期的概念
  • vue-next基於響應式系統實現,意味它的依賴不需要顯示宣告(而且是自動的),而react需要手動宣告依賴陣列