欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文詳解VueUse中useAsyncState的實現(xiàn)原理

 更新時間:2024年01月12日 08:38:27   作者:丶遠方  
在Vue 3 Composition API中,我們可以使用自定義鉤子函數(shù)來封裝可復用的邏輯,useAsyncState是一個用于管理異步狀態(tài)的自定義鉤子函數(shù),本文將給大家介紹一下useAsyncState的實現(xiàn)原理,感興趣的朋友可以參考下

useAsyncState是一個用于管理異步狀態(tài)的自定義鉤子函數(shù)。它是你簡化異步操作的最佳拍檔,就像魚兒離不開水,雄鷹離不開天空,你老婆離不開你,同時異步也離不開 useAsyncState,它簡化了在Vue組件中處理異步操作的過程,如發(fā)送網(wǎng)絡請求、加載數(shù)據(jù)或執(zhí)行其他耗時的任務。

背景

在Vue 3 Composition API中,我們可以使用自定義鉤子函數(shù)來封裝可復用的邏輯。useAsyncState是一個強大而靈活的自定義鉤子函數(shù),幫助我們管理異步操作的狀態(tài),使代碼更簡潔、可讀性更強。

我們先來看一下我們平時在項目開發(fā)的過程中如何使用異步狀態(tài):

<template>
  <div>{{ data }}</div>
</template>

<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import { getData } from './api'

const data = ref(null)
const loading = ref(false)
function loadData() {
  loading.value = true
  getData()
    .then(res => {
      data.value = res
    })
    .catch(e => {
      console.log(e)
    })
    .finally(() => {
      loading.value = false
    })
}

onMounted(() => {
  loadData()
})
</script>

在上面的代碼中,我們可以看到,我們需要定義一個data變量來存儲異步操作的結果,還需要定義一個loading變量來存儲異步操作的加載狀態(tài),還需要定義一個loadData函數(shù)來執(zhí)行異步操作,當異步操作開始時,我們需要將loading設置為true,當異步操作結束時,我們需要將loading設置為false,當異步操作成功時,我們需要將結果賦值給data,在這段代碼中,我們需要定義兩個變量和一個函數(shù),來處理異步操作,這樣的代碼顯然不夠優(yōu)雅,我們可以通過自定義鉤子函數(shù)來優(yōu)化它。

針對上面的代碼,我們不難發(fā)現(xiàn),當我們需要獲取異步狀態(tài)時,需要一個變量來接受獲取到的異步狀態(tài),有時我們也會需要用到loading屬性來判斷異步操作是否正在加載,為此我們需要完成 useAsyncState 來實現(xiàn)它的功能,我們下來看一下實現(xiàn)后的代碼:

<template>
  <div>{{ data }}</div>
</template>

<script lang="ts" setup>
import { useAsyncState } from './useAsyncState'
import { getData } from './api'
const { data, loading } = useAsyncState(getData, null) // 傳遞異步操作的函數(shù)和初始值
</script>

對此我們使用短短十行代碼,就實現(xiàn)了異步操作的狀態(tài)管理,比起之前的代碼,我們可以看到,我們不需要定義額外的變量和函數(shù),只需要調用useAsyncState函數(shù),就可以獲取異步操作的狀態(tài),這樣的代碼更加簡潔,可讀性更強。

目的

useAsyncState 旨在提供以下功能:

  • 方便管理異步操作的狀態(tài)
  • 處理異步操作的加載中、成功和錯誤等不同狀態(tài)
  • 支持自定義操作,如在成功或失敗時執(zhí)行其他邏輯
  • 提供性能優(yōu)化選項,避免不必要的更新

基礎設計

在實現(xiàn)useAsyncState之前,我們先來初步的設計一下它的結構:

參數(shù)

名稱描述類型必傳默認值
fn用于執(zhí)行異步操作的函數(shù),該函數(shù)返回一個 Promise,在調用返回值 execute 時將會執(zhí)行該函數(shù),將 Promise 結果賦值給 state(...args) => Promise<any>-
initialValue默認值,fn函數(shù)未執(zhí)行完成之前,state將為默認值,該參數(shù)的類型應和 fn 參數(shù)返回的 Promise 結果類型相同Awaited<ReturnType>-

返回值

名稱描述類型
state異步操作的狀態(tài),初始值為"initialValue",當 fn 返回的Promise狀態(tài)完成時,將結果賦值給 stateAwaited<ReturnType>
loading異步操作是否正在加載中,初始值為false,當 fn 執(zhí)行時,狀態(tài)為loadin為true,Promise狀態(tài)完成時,loading為falseboolean
execute執(zhí)行異步操作的函數(shù),調用時會執(zhí)行 fn 函數(shù),重新獲取異步狀態(tài)() => void

注:我們最初的設計是為了方便大家的理解,只實現(xiàn)基本的功能,后續(xù)我們會對其進行改進,使其更加易用。

實現(xiàn)

有了上面的設計,我們就可以開始實現(xiàn)useAsyncState了。首先,我們需要定義一個useAsyncState函數(shù),該函數(shù)接受兩個參數(shù),分別是fninitialValue,并返回一個對象,該對象包含多個屬性。

import { ref, Ref } from 'vue'

interface UseAsyncStateReturnType<T> {
  state: Ref<T>
  loading: Ref<boolean>
  execute: () => void
}

/**
 * 響應式異步狀態(tài)管理
 * @param {() => Promise<T>} fn
 * @param {T} initialValue
 * @returns {UseAsyncStateReturnType<T>}
 */
export function useAsyncState<T>(
  fn: () => Promise<T>,
  initialValue: T
): UseAsyncStateReturnType<T> {
  // 用于保存異步狀態(tài)的 ref,默認為初始值
  const state = ref<T>(initialValue)
  // loading 狀態(tài),默認為 false
  const loading = ref<boolean>(false)

  async function execute() {
    // 將 loading 狀態(tài)設置為 true
    loading.value = true
    try {
      const data = await fn()
    } finally {
      // 將 loading 狀態(tài)設置為 false
      loading.value = false
    }
  }

  return {
    state,
    loading,
    execute
  }
}

在上面的代碼中,我們實現(xiàn)了 useAsyncState 的基本功能,它接受兩個參數(shù),分別是 fn 和 initialValue,并返回一個對象,該對象包含我們約定的屬性。

此時我們的 useAsyncState 就已經完成了,我們可以在組件中去使用它

<template>
  <div>
    <div v-if="loading">Loading...</div>
    <div v-else-if="state">Data: {{ state }}</div>
    <div v-else>Error</div>
    <button @click="execute">Execute</button>
  </div>
</template>

<script lang="ts" setup>
  import { useAsyncState } from './useAsyncState'

  const { state, loading, execute } = useAsyncState(
    () => new Promise(resolve => setTimeout(() => resolve('data'), 1000)),
    []
  )

  execute()
</script>

在使用過程中,我們發(fā)現(xiàn)useAsyncState還有一些不足之處:

  • 需要手動調用execute函數(shù),才能執(zhí)行異步操作
  • 調用 execute 函數(shù)時,無法傳遞參數(shù)
  • 無法處理異步操作的錯誤
  • 如果我們需要再響應成功和失敗的情況下,執(zhí)行不同的操作,就需要在execute函數(shù)中添加額外的邏輯

為了解決上面的問題,我們可以對useAsyncState進行改進,使其更加易用。

改進

功能改進

我們針對上面的問題,梳理一下我們的解決方案:

  • 添加 immediate 參數(shù),用于控制是否立即執(zhí)行異步操作
  • 在返回值中添加 error 屬性,用于存儲異步操作的錯誤信息
  • 添加 onSuccessonError 參數(shù),用于在異步操作成功和失敗時執(zhí)行額外的操作
  • 在調用 execute 函數(shù)時,無法傳遞參數(shù),我們可以將 execute 函數(shù)改為接受一個參數(shù),該參數(shù)為 fn 函數(shù)的參數(shù)

當我們改進后,useAsyncState 的結構如下:

import { ref, Ref } from 'vue'

interface UseAsyncStateReturnType<T, P extends any[]> {
  state: Ref<T>
  loading: Ref<boolean>
  execute: (...args: P) => void
  error: Ref<unknown>
}

interface UseAsyncStateOptions<T> {
  immediate?: boolean
  onSuccess?: (data: T) => void
  onError?: (e: unknown) => void
}

export function useAsyncState<T, P extends any[]>(
  fn: (...args: P) => Promise<T>,
  initialValue: T,
  options: UseAsyncStateOptions<T> = {}
): UseAsyncStateReturnType<T, P> {
  // 解構 options 參數(shù)
  const { immediate = false, onError, onSuccess } = options

  // 函數(shù)執(zhí)行結果,默認為初始值
  const state = ref<T>(initialValue) as Ref<T>
  // loading 狀態(tài),默認為 false
  const loading = ref<boolean>(false)

  const error = ref<unknown>(null)

  async function execute(...args: any[]) {
    // 在執(zhí)行異步動作之前將 error 設置為 null
    error.value = null
    // 將 loading 狀態(tài)設置為 true
    loading.value = true
    try {
      const data = await fn(...(args as P))
      onSuccess?.(data)
    } catch (e: unknown) {
      error.value = error
      onError?.(e)
    } finally {
      // 將 loading 狀態(tài)設置為 false
      loading.value = false
    }
  }

  if (immediate) {
    // 如果 immediate 為 true,則立即執(zhí)行異步操作
    execute()
  }

  return {
    state,
    loading,
    execute,
    error
  }
}

在上面的代碼中,我們添加了 error 屬性,用于存儲異步操作的錯誤信息,當異步操作成功時,我們會將 error 設置為 null,當異步操作失敗時,我們會將 error 設置為錯誤信息。

性能優(yōu)化

在上述代碼中,我們將 state 定義為 Ref 類型,但是 Ref 是一個深度的響應式對象,在大部分情況下,我們使用 useAsyncState 獲取到的數(shù)據(jù)只是用來做展示,所以我們應該避免使用 Ref,而是使用 ShallowRef 來代替,ShallowRef 它只會在修改ref.value時才會觸發(fā)更新,而不會在修改ref.value的屬性時觸發(fā)更新。

import { ref, Ref, shallowRef } from 'vue'

interface UseAsyncStateReturnType<T, P extends any[]> {
  state: Ref<T>
  loading: Ref<boolean>
  execute: (...args: P) => void
  error: Ref<unknown>
}

interface UseAsyncStateOptions<T> {
  immediate?: boolean
  onSuccess?: (data: T) => void
  onError?: (e: unknown) => void
  shallow?: boolean
}

export function useAsyncState<T, P extends any[]>(
  fn: (...args: P) => Promise<T>,
  initialValue: T,
  options: UseAsyncStateOptions<T> = {}
): UseAsyncStateReturnType<T, P> {
  // 解構 options 參數(shù)
  const { immediate = false, shallow = true, onError, onSuccess } = options

  // 函數(shù)執(zhí)行結果,默認為初始值
  const state = (shallow ? ref : shallowRef)<T>(initialValue) as Ref<T>
  // loading 狀態(tài),默認為 false
  const loading = ref<boolean>(false)

  const error = shallowRef<unknown>(null)

  async function execute(...args: any[]) {
    // 在執(zhí)行異步動作之前將 error 設置為 null
    error.value = null
    // 將 loading 狀態(tài)設置為 true
    loading.value = true
    try {
      const data = await fn(...(args as P))
      onSuccess?.(data)
    } catch (e: unknown) {
      error.value = error
      onError?.(e)
    } finally {
      // 將 loading 狀態(tài)設置為 false
      loading.value = false
    }
  }

  if (immediate) {
    // 如果 immediate 為 true,則立即執(zhí)行異步操作
    execute()
  }

  return {
    state,
    loading,
    execute,
    error
  }
}

至此,我們的 useAsyncState 就已經完成了。

使用

我們可以在組件中去使用 useAsyncState,來獲取異步數(shù)據(jù)

<template>
  <div>
    <div v-if="loading">Loading...</div>
    <div v-else-if="state">Data: {{ state }}</div>
    <div v-else>Error</div>
    <button @click="execute">Execute</button>
  </div>
</template>

<script lang="ts" setup>
  import { useAsyncState } from './useAsyncState'

  const { state, loading, execute } = useAsyncState(
    () => new Promise(resolve => setTimeout(() => resolve('data'), 1000)),
    '',
    {
      immediate: true,
      onSuccess: data => console.log(data),
      onError: error => console.log(error)
    }
  )
</script>

我們來看一下它的效果

總結

在本篇文章中,我們實現(xiàn)了一個 useAsyncState,它可以幫助我們更加方便的獲取異步數(shù)據(jù),同時也可以幫助我們處理異步操作的錯誤,以及在異步操作成功和失敗時執(zhí)行額外的操作。

以上就是一文詳解VueUse中useAsyncState的實現(xiàn)原理的詳細內容,更多關于VueUse useAsyncState實現(xiàn)原理的資料請關注腳本之家其它相關文章!

相關文章

  • 如何基于Vue制作一個猜拳小游戲

    如何基于Vue制作一個猜拳小游戲

    Vue.js作為目前最熱門最具前景的前端框架之一,其提供了一種幫助我們快速構建并開發(fā)前端項目的新的思維模式,下面這篇文章主要給大家介紹了關于如何基于Vue制作一個猜拳小游戲的相關資料,需要的朋友可以參考下
    2023-01-01
  • 教你使用vue-autofit 一行代碼搞定自適應可視化大屏

    教你使用vue-autofit 一行代碼搞定自適應可視化大屏

    這篇文章主要為大家介紹了使用vue-autofit 一行代碼搞定自適應可視化大屏教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • 在vue中使用公共過濾器filter的方法

    在vue中使用公共過濾器filter的方法

    這篇文章主要介紹了在vue中使用公共過濾器filter的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06
  • Vue中

    Vue中"This dependency was not found"問題的解決方法

    這篇文章主要介紹了Vue中"This dependency was not found"的問題的解決方法,需要的朋友可以參考下
    2018-06-06
  • Vuex之module使用方法及場景說明

    Vuex之module使用方法及場景說明

    這篇文章主要介紹了Vuex之module使用方法及場景說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue版本vue2.9.6升級到vue3.0的詳細步驟

    Vue版本vue2.9.6升級到vue3.0的詳細步驟

    vue版本升級相信大家應該都遇到過,下面這篇文章主要給大家介紹了關于Vue版本vue2.9.6升級到vue3.0的詳細步驟,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • Vue如何下載本地靜態(tài)資源static文件夾

    Vue如何下載本地靜態(tài)資源static文件夾

    這篇文章主要介紹了Vue如何下載本地靜態(tài)資源static文件夾,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • Element的穿梭框數(shù)據(jù)量大時點擊全選卡頓的解決方案

    Element的穿梭框數(shù)據(jù)量大時點擊全選卡頓的解決方案

    本文主要介紹了Element的穿梭框數(shù)據(jù)量大時點擊全選卡頓的解決方案,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Element-plus側邊欄踩坑的問題解決

    Element-plus側邊欄踩坑的問題解決

    本文主要介紹了Element-plus側邊欄踩坑的問題解決,主要解決了el-menu直接嵌套el-menu-item菜單,折疊時不會出現(xiàn)文字顯示和小箭頭無法隱藏的問題,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • Vue項目接入Paypal實現(xiàn)示例詳解

    Vue項目接入Paypal實現(xiàn)示例詳解

    這篇文章主要介紹了Vue項目接入Paypal實現(xiàn)示例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-06-06

最新評論