Vue中hook的使用示例

本文舉出兩個(gè)hook使用的示例,方便理解hook的使用。選用ant-design-vue UI框架作為演示。

封裝下拉框hook

我們?cè)讷@取下拉框字典前會(huì)有個(gè)請(qǐng)求過(guò)程,那現(xiàn)在將請(qǐng)求過(guò)程封裝入hook中。我們先分析下所需實(shí)現(xiàn)的代碼:發(fā)送請(qǐng)求的方法、獲得下拉字典及控制請(qǐng)求狀態(tài)的變量、呈現(xiàn)組件。
下面是發(fā)送請(qǐng)求的代碼:

// api.ts
export const getRemoteData = ()=>{
  return new Promise<any[]>((resolve, reject)=>{
    setTimeout(()=>{
      if(Math.random() > 0.2){
        resolve([{key:1,label:'蘋(píng)果',value:1},{key:2,label:'香蕉',value:2},{key:3,label:'橘子',value:3}]);
      }else{
        reject(new Error('意外錯(cuò)誤'));
      }
    }, 1000);
  });
}

下面是獲得下拉字典及控制請(qǐng)求狀態(tài)的變量的hook代碼:

// hook.ts
import { onMounted, reactive, ref } from 'vue';

// 定義下拉框接受的數(shù)據(jù)格式
interface SelectOption {
  value: string;
  label: string;
  disabled?: boolean;
  key?: string;
}
// 定義hook方法入?yún)㈩愋?interface FetchSelectProps {
  apiFun:()=>Promise<any[]>;
}

export default function useFetchSelect(props:FetchSelectProps){
  const { apiFun } = props;
  const options = ref<SelectOption[]>([]);
  const loading = ref(false);

  // 包裝發(fā)送請(qǐng)求函數(shù)
  const loadData = ()=>{
    loading.value = true;
    options.value = [];
    return apiFun().then(res=>{
      loading.value = false;
      options.value = res;
      return res;
    }, (err)=>{
      loading.value = false;
      options.value = [{
        value: -1,
        label: err.message,
        disabled: true,
      }]
      return Promise.reject(err);
    });
  }
  onMounted(loadData);
  return reactive({options,loading});
}

呈現(xiàn)組件代碼:

// index.vue
<script setup lang="ts">
import useFetchSelect from './hook';
import { getRemoteData } from './api';

const selectBind = useFetchSelect({apiFun:getRemoteData}); // 如果不傳入多個(gè)參數(shù),可以用基本變量
</script>

<template>
  <a-select :="selectBind"></a-select>
</template>
字典獲取成功.gif

字典獲取失敗.gif

封裝按鈕加載狀態(tài)hook

現(xiàn)在的按鈕都需要個(gè)變量來(lái)展示加載狀態(tài),給予用戶更好的體驗(yàn),同時(shí)可以防止用戶多次點(diǎn)擊,雖然只是個(gè)增加一個(gè)變量狀態(tài),但是寫(xiě)多了也煩。實(shí)現(xiàn)功能所需的代碼同上。
下面是發(fā)送請(qǐng)求的代碼:

// api.ts
function submitApi(text:string){
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      if(Math.random()>0.5){
        resolve({
          status:'ok',
          text:text,
        })
      }else{
        reject(new Error('意外錯(cuò)誤'));
      }
    },1000)
  })
}

下面是包裝發(fā)送請(qǐng)求的hook代碼:

// hook.ts
import { ref } from 'vue';
import type { Ref } from 'vue';

// 定義發(fā)送請(qǐng)求方法的類型
type TApiFun<TData, TParams extends Array<any>> = (...params: TParams)=>Promise<TData>;

interface AutoRequestOptions {
  loading?:boolean; // 定義初始狀態(tài)
  onSuccess?:(data:any)=>void; // 定義接口調(diào)用后出發(fā)的提示彈框回調(diào);
}

type AutoRequestResult<TData, TParams extends Array<any>> = [Ref<boolean>,TApiFun<TData,TParams>];

// 相當(dāng)于在api方法前 加了層修飾器
export default function useAutoRequest<TData, TParams extends any[] = any[]>(fun:TApiFun<TData,TParams>, options?:AutoRequestOptions):AutoRequestResult<TData,TParams> {
  const {loading = false, onSuccess} = options||{loading:false};
  const requestLoading = ref(loading);
  const run:TApiFun<TData, TParams> = (...params) => {
    requestLoading.value = true;
    return fun(...params).then((res) => {
      onSuccess && onSuccess(res);
      return res;
    }).finally(() => {
      requestLoading.value = false;
    })
  }
  return [requestLoading,run]
}

下面是呈現(xiàn)組件:

// index.vue
<script setup lang="ts">
import useAutoRequest from './hook';
import { submitApi } from './api';

const [loading, submit]= useAutoRequest(submitApi); // 可選傳成功后彈框方法

const onSubmit = ()=>{
  submit('aaa').then(res=>{
    console.log('res', res);
  })
}
</script>

<template>
  <a-button :loading="loading" @click="onSubmit">提交</a-select>
</template>
按鈕加載狀態(tài).gif
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容