前言:
剛接觸、搭建Nuxt3項目的過程還是有點懵的,有種摸石頭過河的感覺,對于網絡請求這塊,與之前的Vue3項目有所區別,在Vue項目通常使用axios這個庫進行網絡請求,但在Nuxt項目并不推薦,因為有內置 fetch 相關...接下來一起學習一下Nuxt3數據請求的點點滴滴吧~
文檔:
數據獲取 · 快速入門 Nuxt
關鍵:
- useFetch?是在組件設置函數中處理數據獲取的最簡單方法。
- $fetch?可以根據用戶交互進行網絡請求。
- useAsyncData?結合?
$fetch
,提供了更精細的控制。
講解:
useAsyncData:
- 提供了一種在SSR友好的組合式中訪問異步解析數據的方式
- 注意,setup期間,這里結合了$fetch,并且設置了一個key,一個唯一的鍵,用于確保數據獲取可以在請求中正確去重
-
<script setup> const { data, pending, error, refresh } = await useAsyncData('mountains',() => $fetch('https://api.nuxtjs.dev/mountains') ) </script>
- 當 CMS 或第三方提供自己的查詢層時。在這種情況下,您可以使用?useAsyncData?來封裝您的調用,并仍然保持組合函數提供的好處。?
$fetch:
- Nuxt使用?ofetch?來全局暴露`$fetch`輔助函數,用于在Vue應用程序或API路由中進行HTTP請求?
- 源碼:nuxt/packages/nuxt/src/app/entry.ts at main · nuxt/nuxt · GitHub
$fetch
是在Nuxt中進行HTTP調用的首選方式,而不是為Nuxt 2設計的@nuxt/http和@nuxtjs/axios。- 比如,你的頁面有給用戶提供交互的(按鈕),那么就可以使用 $fetch ,不然控制臺會有警告,網上就有不少人是在交互的時候使用useFetch而出現問題,看下面這篇文章
- 警告:[nuxt] [useFetch] Component is already mounted, please use $fetch instead. See https://nuxt.com/docs/getting-started/data-fetching
- Nuxt 3:正確的方法 --- useFetch in Nuxt 3: The Proper Way (alex.party)
- 請觀察以下調用接口的時機:setup | click
-
<script setup lang="ts"> // 在SSR中數據將被獲取兩次,一次在服務器端,一次在客戶端。 const dataTwice = await $fetch('/api/item')// 在SSR中,數據僅在服務器端獲取并傳遞到客戶端。 const { data } = await useAsyncData('item', () => $fetch('/api/item'))// 你也可以使用useFetch作為useAsyncData + $fetch的快捷方式 const { data } = await useFetch('/api/item') </script>
<script setup lang="ts"> function contactForm() {$fetch('/api/contact', {method: 'POST',body: { hello: 'world '}}) } </script><template><button @click="contactForm">聯系我們</button> </template>
useFetch :
- 使用一個與SSR兼容的可組合函數從API端點獲取數據。
- 包裝了useAsyncData和$fetch,它返回響應式的可組合函數,并處理將響應添加到Nuxt的負載中,以便在頁面水合時可以從服務器傳遞給客戶端,而無需在客戶端重新獲取數據。
- (水合的概念在文檔的渲染模式有講解:渲染模式 · 關鍵概念 (nuxt.com.cn))
- 提供了攔截器
-
const { data, pending, error, refresh } = await useFetch('/api/auth/login', {onRequest({ request, options }) {// 設置請求頭options.headers = options.headers || {}options.headers.authorization = '...'},onRequestError({ request, options, error }) {// 處理請求錯誤},onResponse({ request, response, options }) {// 處理響應數據localStorage.setItem('token', response._data.token)},onResponseError({ request, response, options }) {// 處理響應錯誤} })
- 事實上,
useFetch(url)
?幾乎等同于?useAsyncData(url, () => $fetch(url))
?- 它是為最常見的用例提供的開發者體驗糖。?
封裝:工廠函數設計請求代碼結構
env:
- 在nuxt.config.ts配置 runtimeConfig,通過useRuntimeConfig()解構,示例:
export default defineNuxtConfig({runtimeConfig: {public: {API_BASE_DEV: 'http://localhost:4000',API_BASE_PROD: 'https://api.example.com/v1'}},
})
- 當然你還可以
?composables:
-
封裝$fetch
- -?composables/useDollarFetchRequest.ts
import { $fetch } from 'ofetch';
import { useRuntimeConfig } from '#app';interface RequestOptions {customBaseURL?: string;[key: string]: any;
}type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';// 請求攔截器
function handleRequest(options: RequestOptions) {options.headers = {...options.headers,'Content-Type': 'application/json',};
}// 響應攔截器
function handleResponse(response: any) {if (response.error) {throw new Error(response.error.message || '響應錯誤');}return response;
}/*** 創建請求方法* @param method*/
function createDollarFetchRequest(method: HttpMethod) {return async function (url: string,data?: any,options: RequestOptions = {}) {const {public: {API_BASE_DEV,API_BASE_PROD}} = useRuntimeConfig();const baseURL = process.env.NODE_ENV === 'production'? API_BASE_PROD: API_BASE_DEV;const requestUrl = new URL(url,options.customBaseURL || baseURL).toString();try {handleRequest(options);const response = await $fetch(requestUrl, {method,body: data,...options,});return handleResponse(response);} catch (error) {console.error('請求錯誤:', error);throw error;}};
}// 提供 $fetch & HTTP 方法 - 統一管理請求 - 再到組件中使用
export const useDollarGet = createDollarFetchRequest('GET');
export const useDollarPost = createDollarFetchRequest('POST');
export const useDollarPut = createDollarFetchRequest('PUT');
export const useDollarDelete = createDollarFetchRequest('DELETE');
-
封裝useFetch
- - composables/useFetchRequest.ts
import { useFetch, useRuntimeConfig } from '#app';
import type { UseFetchOptions } from 'nuxt/app';interface RequestOptions extends UseFetchOptions<any> {customBaseURL?: string;
}type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type HandleRequestOptions = { request: Request; options: RequestOptions };
type HandleResponseOptions = { response: any };// 請求攔截器
function handleRequest({ options }: HandleRequestOptions) {options.headers = {...options.headers,'Content-Type': 'application/json',};
}// 響應攔截器
function handleResponse({ response }: HandleResponseOptions) {if (response._data.error) {throw new Error(response._data.error.message || '響應錯誤');}return response._data;
}/*** 創建請求方法* @param method*/
function createUseFetchRequest(method: HttpMethod) {return async function (url: string,data?: any,options: RequestOptions = {}) {const {public: {API_BASE_DEV,API_BASE_PROD}} = useRuntimeConfig();const baseURL = process.env.NODE_ENV === 'production'? API_BASE_PROD: API_BASE_DEV;const requestUrl = new URL(url,options.customBaseURL || baseURL).toString();return await useFetch(requestUrl, {...options,method,body: data,onRequest: handleRequest,onResponse: handleResponse});};
}// 提供 useFetch & HTTP 方法 - 統一管理請求 - 再到組件中使用
export const useFetchGet = createUseFetchRequest('GET');
export const useFetchPost = createUseFetchRequest('POST');
export const useFetchPut = createUseFetchRequest('PUT');
export const useFetchDelete = createUseFetchRequest('DELETE');
統一管理 API?
- 調用 $fetch 示例:
import { useDollarGet } from '~/composables/useDollarFetchRequest';export const getDocsApi = () => useDollarGet('/docs/list');
<template><div><button @click="handleGetUserInfo">獲取用戶信息</button></div><HomeCover /><HomeIntro /><HomeCadre /><HomeJoinUs /><BackToTop />
</template><script setup lang="ts">
import HomeCover from './HomeCover.vue';
import HomeIntro from './HomeIntro.vue';
import HomeCadre from './HomeCadre.vue';
import HomeJoinUs from './HomeJoinUs.vue';
import { getDocsApi } from '../../api/home/joinUs';const handleGetUserInfo = async () => {try {const data = await getDocsApi();console.log('文檔列表:', data);} catch (error) {console.error('獲取文檔列表出錯:', error);}
};
</script>
- 調用 useFetch 示例
<script setup lang="ts">
import { getDocsApi } from '../../api/home/joinUs';try {const response = await getDocsApi();console.log('文檔列表:', response.data.value);
} catch (error) {console.error('獲取文檔列表出錯:', error);
}</script>
結果:
?
?歡迎三連,以及在評論區討論,如果有不對的還請告知糾正?