API: fetchBaseQuery reference">API: fetchBaseQuery reference">
跳到主要內容

fetchBaseQuery

這是一個包覆在 fetch 周圍非常小的包裝器,旨在簡化 HTTP 要求。它並非 axiossuperagent 或任何其他更重量級函式庫的全面替換品,但它將涵蓋您絕大多數的 HTTP 要求需求。

fetchBaseQuery 是產生與 RTK Query 的 baseQuery 組態選項相容的資料擷取方法的工廠函式。它採用 fetch 的 RequestInit 介面的所有標準選項,以及 baseUrlprepareHeaders 函式、一個選用的 fetch 函式、一個 paramsSerializer 函式,以及一個 timeout

基本用法

要使用它,請在建立 API 服務定義時匯入它,將它呼叫為 fetchBaseQuery(options),並將結果傳遞為 createApi 中的 baseQuery 欄位

src/services/pokemon.ts
// Or from '@reduxjs/toolkit/query/react'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

export const pokemonApi = createApi({
// Set the baseUrl for every endpoint below
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
endpoints: (builder) => ({
getPokemonByName: builder.query({
// Will make a request like https://pokeapi.co/api/v2/pokemon/bulbasaur
query: (name: string) => `pokemon/${name}`,
}),
updatePokemon: builder.mutation({
query: ({ name, patch }) => ({
url: `pokemon/${name}`,
// When performing a mutation, you typically use a method of
// PATCH/PUT/POST/DELETE for REST endpoints
method: 'PATCH',
// fetchBaseQuery automatically adds `content-type: application/json` to
// the Headers and calls `JSON.stringify(patch)`
body: patch,
}),
}),
}),
})

簽章

fetchBaseQuery 簽章
type FetchBaseQuery = (
args: FetchBaseQueryArgs,
) => (
args: string | FetchArgs,
api: BaseQueryApi,
extraOptions: ExtraOptions,
) => FetchBaseQueryResult

type FetchBaseQueryArgs = {
baseUrl?: string
prepareHeaders?: (
headers: Headers,
api: Pick<
BaseQueryApi,
'getState' | 'extra' | 'endpoint' | 'type' | 'forced'
>,
) => MaybePromise<Headers | void>
fetchFn?: (
input: RequestInfo,
init?: RequestInit | undefined,
) => Promise<Response>
paramsSerializer?: (params: Record<string, any>) => string
isJsonContentType?: (headers: Headers) => boolean
jsonContentType?: string
timeout?: number
} & RequestInit

type FetchBaseQueryResult = Promise<
| {
data: any
error?: undefined
meta?: { request: Request; response: Response }
}
| {
error: {
status: number
data: any
}
data?: undefined
meta?: { request: Request; response: Response }
}
>

參數

baseUrl

(必填)

通常是類似 https://api.your-really-great-app.com/v1/ 的字串。如果您未提供 baseUrl,它會預設為從發出要求的位置的相對路徑。您很可能永遠都應該指定這個

prepareHeaders

(選填)

允許您注入每個要求的標頭。您可以在端點層級指定標頭,但通常您會希望在此設定常見標頭,例如 authorization。作為一種便利機制,第二個引數允許您使用 getState 存取您的 redux 儲存,以防您在那裡儲存您需要的資訊,例如驗證權杖。此外,它提供存取 extraendpointtypeforced 以解鎖更精細的條件行為。

您可以直接變更 headers 引數,傳回它是選填的。

prepareHeaders 簽章
type prepareHeaders = (
headers: Headers,
api: {
getState: () => unknown
extra: unknown
endpoint: string
type: 'query' | 'mutation'
forced: boolean | undefined
},
) => Headers | void

paramsSerializer

(選填)

一個函式,可用於對傳遞到 params 的資料套用自訂轉換。如果您未提供這個,params 會直接傳遞給 new URLSearchParams()。對於某些 API 整合,您可能需要利用這個來使用類似 query-string 函式庫來支援不同的陣列類型。

fetchFn

(選填)

一個覆寫 window 上預設值的 fetch 函式。在需要利用 isomorphic-fetchcross-fetch 的 SSR 環境中可能很有用。

timeout

(選填)

以毫秒為單位的數字,表示請求在逾時之前可以花費的最長時間。

isJsonContentType

(選填)

接收 Headers 物件並決定 FetchArgs 參數的 body 欄位是否應透過 JSON.stringify() 轉換成字串的回呼函式。

預設實作會檢查 content-type 標頭,並會比對 "application/json""application/vnd.api+json" 等值。

jsonContentType

(選填)

在自動設定沒有明確 content-type 標頭的可轉換為 json 的主體的請求的 content-type 標頭時使用。預設為 "application/json"

常見使用模式

在請求上設定預設標頭

prepareHeaders 最常見的用例是自動為 API 請求包含 authorization 標頭。

"設定
import { fetchBaseQuery } from '@reduxjs/toolkit/query'
import type { RootState } from './store'

const baseQuery = fetchBaseQuery({
baseUrl: '/',
prepareHeaders: (headers, { getState }) => {
const token = (getState() as RootState).auth.token

// If we have a token set in state, let's assume that we should be passing it.
if (token) {
headers.set('authorization', `Bearer ${token}`)
}

return headers
},
})

個別查詢選項

有更多行為可以在每個請求的基礎上定義。query 欄位可能會傳回包含任何可供 RequestInit 介面使用的預設 fetch 選項的物件,以及這些其他選項

端點請求選項
interface FetchArgs extends RequestInit {
url: string
params?: Record<string, any>
body?: any
responseHandler?:
| 'json'
| 'text'
| `content-type`
| ((response: Response) => Promise<any>)
validateStatus?: (response: Response, body: any) => boolean
timeout?: number
}

const defaultValidateStatus = (response: Response) =>
response.status >= 200 && response.status <= 299

設定主體

預設情況下,fetchBaseQuery 假設您發出的每個請求都會是 json,因此在這些情況下,您所要做的就是設定 url,並在適當的時候傳遞 body 物件。對於其他實作,您可以手動設定 Headers 來指定內容類型。

json

 // omitted
endpoints: (builder) => ({
updateUser: builder.query({
query: (user: Record<string, string>) => ({
url: `users`,
method: 'PUT',
body: user // Body is automatically converted to json with the correct headers
}),
}),

text

 // omitted
endpoints: (builder) => ({
updateUser: builder.query({
query: (user: Record<string, string>) => ({
url: `users`,
method: 'PUT',
headers: {
'content-type': 'text/plain',
},
body: user
}),
}),

設定查詢字串

fetchBaseQuery 提供一個簡單的機制,透過將物件傳遞給 new URLSearchParms(),將 object 轉換成序列化查詢字串。如果這不符合您的需求,您有兩個選項

  1. paramsSerializer 選項傳遞給 fetchBaseQuery 以套用自訂轉換
  2. 建立您自己的查詢字串並在 url 中設定
 // omitted
endpoints: (builder) => ({
updateUser: builder.query({
query: (user: Record<string, string>) => ({
url: `users`,
// Assuming no `paramsSerializer` is specified, the user object is automatically converted
// and produces a url like /api/users?first_name=test&last_name=example
params: user
}),
}),

剖析回應

預設情況下,fetchBaseQuery 假設您收到的每個 Response 都會剖析為 json。如果您不希望發生這種情況,您可以透過指定替代回應處理常式(例如 text)來自訂行為,或完全控制並使用接受原始 Response 物件的自訂函數 — 讓您可以使用任何 Response 方法

responseHandler 欄位可以是

type ResponseHandler =
| 'content-type'
| 'json'
| 'text'
| ((response: Response) => Promise<any>)

"json""text" 值指示 fetchBaseQuery 使用對應的擷取回應方法來讀取主體。content-type 會檢查標頭欄位以首先確定這是否看起來是 JSON,然後使用這兩個方法之一。回呼讓您可以自行處理主體。

將回應剖析為文字
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

export const customApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => ({
url: `users`,
// This is the same as passing 'text'
responseHandler: (response) => response.text(),
}),
}),
}),
})
關於傳回未定義主體的回應的注意事項

如果您對只傳回 200 且主體未定義的 API 提出 json 要求,fetchBaseQuery 會將其傳遞為 undefined,並且不會嘗試將其剖析為 json。這在某些 API 中很常見,特別是在 delete 要求中。

處理非標準回應狀態碼

預設情況下,fetchBaseQueryreject 任何狀態碼不是 2xxResponse,並將其設為 error。這與你使用 axios 和其他熱門函式庫時最有可能遇到的行為相同。如果你正在處理非標準 API,你可以使用 validateStatus 選項自訂此行為。

使用自訂的 validateStatus
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

export const customApi = createApi({
// Set the baseUrl for every endpoint below
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => ({
url: `users`,
// Example: we have a backend API always returns a 200,
// but sets an `isError` property when there is an error.
validateStatus: (response, result) =>
response.status === 200 && !result.isError,
}),
}),
}),
})

為請求新增自訂逾時

預設情況下,fetchBaseQuery 沒有設定預設逾時值,表示你的請求會持續等待,直到你的 API 解決請求或達到瀏覽器的預設逾時(通常為 5 分鐘)。大多數時候,這不是你想要的。使用 fetchBaseQuery 時,你可以對 baseQuery 或個別端點設定 timeout。同時指定兩個選項時,端點值將優先。

設定逾時值
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

export const api = createApi({
// Set a default timeout of 10 seconds
baseQuery: fetchBaseQuery({ baseUrl: '/api/', timeout: 10000 }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => ({
url: `users`,
// Example: we know the users endpoint is _really fast_ because it's always cached.
// We can assume if its over > 1000ms, something is wrong and we should abort the request.
timeout: 1000,
}),
}),
}),
})