@vue/composition-api速成課(通俗易懂版)

@vue/composition-api速成課(通俗易懂版)

作者: frank

轉發鏈接:https://mp.weixin.qq.com/s/PYOq1RUVvQXR3F7bnH453A

前言

Composition API 將是 Vue 3 的核心功能,它具有許多更改和性能改進。我們也可以在 Vue 2 中通過 npm 插件@vue/composition-api 使用它。本文重點將帶你瞭解:

  1. @vue/composition-api

    常見 api 使用
  2. vue3 代碼邏輯提取和複用
  3. 如何使用

    provide+inject

    替代

    vuex

    方案

vue2 使用 composition-api

主文件 main.ts 或者 app.vue 添加

<code>import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
/<code>

Composition API 不再傳入 data、mounted 等參數, 通過引入的 ref、onMounted等方法實現數據的雙向綁定、生命週期函數的執行。

核心語法

reactive:接收一個普通對象然後返回該普通對象的響應式代理。

ref:接受一個參數值並返回一個響應式且可改變的 ref 對象。ref 對象擁有一個指向內部值的單一屬性 .value。

computed:傳入一個 getter 函數,返回一個默認不可手動修改的 ref 對象。

readonly:傳入一個對象(響應式或普通)或 ref,返回一個原始對象的只讀代理。一個只讀的代理是“深層的”,對象內部任何嵌套的屬性也都是隻讀的。

watchEffect:立即執行傳入的一個函數,並響應式追蹤其依賴,並在其依賴變更時重新運行該函數。可顯式的調用返回值以停止偵聽。

watch:全等效於 2.x this.\$watch (以及 watch 中相應的選項)。

setup 函數

現在要介紹的第一個 API 就是 setup 函數。setup 函數是一個新的組件選項。作為在組件內使用 Composition API 的入口點。先看個簡單 demo

<code>
  

 
/<code>

1、調用時機

創建組件實例,然後初始化 props ,緊接著就調用 setup 函數。從 vue2 生命週期鉤子的視角來看,它會在 beforeCreate 鉤子之後,created 之前被調用。

2、模板中使用

如果 setup 返回一個對象,則對象的屬性將會被合併到組件模板的渲染上下文。

3、渲染函數 / JSX 中使用

setup 也可以返回一個函數,函數中也能使用當前 setup 函數作用域中的響應式數據:

<code>import { h, ref, reactive } from '@vue/composition-api'

export default {
  setup() {
    const count = ref(0)
    const object = reactive({ foo: 'bar' })

    return () => h('div', [count.value, object.foo])
  },
}
/<code>

4、兩個參數props(注意 props 對象是響應式的),context(上下文對象,從原來 2.x 中 this 選擇性地暴露了一些 property。)

<code>const MyComponent = {
  setup(props, context) {
    let {
      attrs,
      emit,
      isServer,
      listeners,
      parent,
      refs,
      root,
      slots,
      ssrContext,
    } = context
  },
}
/<code>

ref & reactive

在 App.vue 中,點擊事件綁定了 increase,然後修改了 count, 但是頁面並沒有發生改變,這是因為 setup 函數返回的對象中 count 不是響應式數據, 那麼如何創建響應式數據呢?此時就要掌握響應式系統 API,我們可以使用 ref 和 reactive 創建。

<code>
  


 
/<code>

接受一個參數值並返回一個響應式且可改變的 ref 對象。ref 對象擁有一個指向內部值的單一屬性 .value。

當 ref 作為渲染上下文的屬性返回(即在 setup() 返回的對象中)並在模板中使用時, 它會自動解套,無需在模板內額外書寫 .value

Vue 本身已經有 "ref" 的概念了。但只是為了在模板中獲取 DOM 元素或組件實例 (“模板引用”)。新的 ref 系統同時用於邏輯狀態和模板引用。

reactive 接收一個普通對象然後返回該普通對象的響應式代理。

響應式轉換是“深層的”:會影響對象內部所有嵌套的屬性。基於 ES2015 的 Proxy 實現,返回的代理對象不等於原始對象。建議僅使用代理對象而避免依賴原始對象。

不要解構返回的代理對象,那樣會使其失去響應性:

<code>
  


 
/<code>

toRef 和 toRefs

那如果我們真的想展開 state 的屬性,在模板使用 count 而不是 state.count 的寫法那怎麼辦呢?我們可以使用 toRef 和 toRefs 這兩個 API,進行轉換成 ref 對象,之前已經介紹了 ref 對象是可以直接在模板中使用的。

toRef 可以用來為一個 reactive 對象的屬性創建一個 ref。這個 ref 可以被傳遞並且能夠保持響應性。

<code>
  


 
/<code>

把一個響應式對象轉換成普通對象,該普通對象的每個 property 都是一個 ref ,和響應式對象 property 一一對應。

computed & watch

<code>const countDouble = computed(() => count.value * 2)
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)
/<code>

代碼邏輯提取和複用

Composition API 的第一個明顯優勢是很容易提取邏輯。解決了

邏輯提取

<code>export const useCount = (number) => {
  const count = ref(0)
  const increase = () => {
    count.value += 1
  }
  const reset = () => {
    count.value = 0
  }
  onMounted(() => {
    count.value = number
  })
  return {
    count,
    increase,
    reset,
  }
}
/<code>

代碼複用

<code>// 另外一個文件使用:
const { count, increase } = useCount(1)
console.log(count) //輸出1
increase()
console.log(count) //輸出2
reset()
console.log(count) //輸出0
/<code>

有效的解決了 mixins 複用命名衝突,難以識別命名來自哪個 mixin 文件的問題。

替代 vuex 狀態管理

狀態 store 可以放在一個單一的文件或者目錄裡,比如設置一個全局組件可以只用的配置 config

<code>//context/config.ts
import { provide, inject, ref, onMounted, readonly } from '@vue/composition-api'
const configSymbol: symbol = Symbol()

export const useProvider = {
  setup() {
    let config = ref(null)
    const configServer = async () => {
      // await 一些異步操作,比如api等
      config.value = { name: '名字' }
    }
    onMounted(async () => {
      await configServer()
    })
    provide(configSymbol, {
      //導出只讀的config只有函數內部可以修改狀態
      config: readonly(config),
    })
  },
}

export const useInject = () => {
  return inject(configSymbol)
}
/<code>

在最頂層的組件(例如 main.ts)上注入,config 就可以在所有的組件中使用

<code>import { defineComponent } from '@vue/composition-api'
import { useProvider } from './context/config'
export default defineComponent({
  setup() {
    useProvider()
  },
})
/<code>

業務邏輯頁面使用 config

<code>import { useInject } from './context/config'
const Components = {
  setup() {
    const { config } = useInject()
    console.log(config.value.name) //輸出“名字”
    return {
      config,
    }
  },
}/<code>


分享到:


相關文章: