跳至主要內容

RTK Query 快速入門

您將會學到
  • 如何設定和使用 Redux Toolkit 的「RTK Query」資料擷取功能
先備條件

簡介

歡迎使用 Redux Toolkit 查詢教學!本教學將簡要介紹 Redux Toolkit 的「RTK Query」資料擷取功能,並教導您如何開始正確使用它

資訊

如需更深入的 RTK Query 教學,請參閱 Redux 核心文件網站上的完整 「Redux Essentials」教學

RTK Query 是一種進階資料擷取和快取工具,旨在簡化網頁應用程式中載入資料的常見案例。RTK Query 本身建構在 Redux Toolkit 核心之上,並利用 RTK 的 API,例如 createSlicecreateAsyncThunk 來實作其功能。

RTK Query 包含在 @reduxjs/toolkit 套件中,作為額外的附加元件。您在使用 Redux Toolkit 時不必使用 RTK Query API,但我們認為許多使用者會從 RTK Query 在其應用程式中的資料擷取和快取中受益。

如何閱讀本教學

在本教學中,我們假設您將 Redux Toolkit 與 React 一起使用,但您也可以將其與其他 UI 層一起使用。範例基於 典型的 Create-React-App 資料夾結構,其中所有應用程式程式碼都位於 src 中,但模式可以調整為您使用的任何專案或資料夾設定。

設定您的儲存體和 API 服務

為了了解 RTK Query 的運作方式,讓我們逐步了解一個基本使用範例。在本範例中,我們假設您正在使用 React,並希望使用 RTK Query 自動產生的 React 勾子。

建立一個 API 服務

首先,我們將建立一個服務定義,查詢公開可用的 PokeAPI

src/services/pokemon.ts
// Need to use the React-specific entry point to import createApi
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import type { Pokemon } from './types'

// Define a service using a base URL and expected endpoints
export const pokemonApi = createApi({
reducerPath: 'pokemonApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
endpoints: (builder) => ({
getPokemonByName: builder.query<Pokemon, string>({
query: (name) => `pokemon/${name}`,
}),
}),
})

// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
export const { useGetPokemonByNameQuery } = pokemonApi

使用 RTK Query 時,通常會在一個地方定義整個 API 定義。這很可能與你在其他函式庫(例如 `swr` 或 `react-query`)中看到的不同,而且有幾個原因。我們的觀點是,相較於在應用程式中不同檔案中擁有 X 個自訂掛勾,將請求、快取失效和一般應用程式組態放在一個中央位置,可以更輕鬆地追蹤它們的行為。

提示

通常,應用程式需要與每個基本 URL 進行通訊,你應該只有一個 API 區段。例如,如果你的網站從 `api/posts` 和 `api/users` 中擷取資料,你會有一個以 `/api/` 為基本 URL 的單一 API 區段,以及 `posts` 和 `users` 的個別端點定義。這可讓你有效利用 自動重新擷取,方法是在端點間定義 標籤 關係。

為了維護性,你可能希望將端點定義分割成多個檔案,同時仍維持包含所有這些端點的單一 API 區段。請參閱 程式碼分割,了解如何使用 `injectEndpoints` 屬性將其他檔案中的 API 端點注入到單一 API 區段定義中。

將服務加入你的儲存體

RTKQ 服務會產生一個「切片簡約器」,應包含在 Redux 根簡約器中,以及一個自訂中介軟體來處理資料擷取。這兩者都需要新增到 Redux 儲存體。

src/store.ts
import { configureStore } from '@reduxjs/toolkit'
// Or from '@reduxjs/toolkit/query/react'
import { setupListeners } from '@reduxjs/toolkit/query'
import { pokemonApi } from './services/pokemon'

export const store = configureStore({
reducer: {
// Add the generated reducer as a specific top-level slice
[pokemonApi.reducerPath]: pokemonApi.reducer,
},
// Adding the api middleware enables caching, invalidation, polling,
// and other useful features of `rtk-query`.
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(pokemonApi.middleware),
})

// optional, but required for refetchOnFocus/refetchOnReconnect behaviors
// see `setupListeners` docs - takes an optional callback as the 2nd arg for customization
setupListeners(store.dispatch)

使用 Provider 包裝您的應用程式

如果您尚未這麼做,請遵循標準模式,將 Redux 儲存體提供給 React 應用程式元件樹的其他部分

src/index.tsx
import * as React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'

import App from './App'
import { store } from './store'

const rootElement = document.getElementById('root')
render(
<Provider store={store}>
<App />
</Provider>,
rootElement
)

在元件中使用查詢

定義服務後,您可以匯入掛勾來提出要求。

src/App.tsx
import * as React from 'react'
import { useGetPokemonByNameQuery } from './services/pokemon'

export default function App() {
// Using a query hook automatically fetches data and returns query values
const { data, error, isLoading } = useGetPokemonByNameQuery('bulbasaur')
// Individual hooks are also accessible under the generated endpoints:
// const { data, error, isLoading } = pokemonApi.endpoints.getPokemonByName.useQuery('bulbasaur')

return (
<div className="App">
{error ? (
<>Oh no, there was an error</>
) : isLoading ? (
<>Loading...</>
) : data ? (
<>
<h3>{data.species.name}</h3>
<img src={data.sprites.front_shiny} alt={data.species.name} />
</>
) : null}
</div>
)
}

提出要求時,您可以透過多種方式追蹤狀態。您隨時可以查看 datastatuserror 來決定要呈現哪個 UI。此外,useQuery 也提供最新要求的公用布林值,例如 isLoadingisFetchingisSuccessisError

基本範例

好的,這很有趣... 但如果您想要同時顯示多隻寶可夢怎麼辦?如果多個元件載入相同的寶可夢會發生什麼事?

進階範例

RTK Query 可確保任何訂閱相同查詢的元件永遠會使用相同的資料。RTK Query 會自動移除重複要求,因此您不必擔心檢查進行中的要求和效能最佳化。讓我們評估以下沙盒 - 請務必查看瀏覽器開發人員工具中的網路面板。您將看到 3 個要求,即使有 4 個訂閱的元件 - bulbasaur 只會提出一個要求,而且載入狀態會在兩個元件之間同步。為了好玩,請嘗試將下拉式選單的值從 Off 變更為 1s,看看這種行為是否會在重新執行查詢時繼續。