RTK Query 快速入門
- 如何設定和使用 Redux Toolkit 的「RTK Query」資料擷取功能
- 了解 Redux 條款和概念
簡介
歡迎使用 Redux Toolkit 查詢教學!本教學將簡要介紹 Redux Toolkit 的「RTK Query」資料擷取功能,並教導您如何開始正確使用它。
如需更深入的 RTK Query 教學,請參閱 Redux 核心文件網站上的完整 「Redux Essentials」教學。
RTK Query 是一種進階資料擷取和快取工具,旨在簡化網頁應用程式中載入資料的常見案例。RTK Query 本身建構在 Redux Toolkit 核心之上,並利用 RTK 的 API,例如 createSlice
和 createAsyncThunk
來實作其功能。
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。
- TypeScript
- JavaScript
// 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
// Need to use the React-specific entry point to import createApi
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
// 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({
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 個自訂掛勾,將請求、快取失效和一般應用程式組態放在一個中央位置,可以更輕鬆地追蹤它們的行為。
將服務加入你的儲存體
RTKQ 服務會產生一個「切片簡約器」,應包含在 Redux 根簡約器中,以及一個自訂中介軟體來處理資料擷取。這兩者都需要新增到 Redux 儲存體。
- TypeScript
- JavaScript
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)
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 應用程式元件樹的其他部分
- TypeScript
- JavaScript
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
)
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
)
在元件中使用查詢
定義服務後,您可以匯入掛勾來提出要求。
- TypeScript
- JavaScript
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>
)
}
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>
)
}
提出要求時,您可以透過多種方式追蹤狀態。您隨時可以查看 data
、status
和 error
來決定要呈現哪個 UI。此外,useQuery
也提供最新要求的公用布林值,例如 isLoading
、isFetching
、isSuccess
和 isError
。
基本範例
好的,這很有趣... 但如果您想要同時顯示多隻寶可夢怎麼辦?如果多個元件載入相同的寶可夢會發生什麼事?
進階範例
RTK Query 可確保任何訂閱相同查詢的元件永遠會使用相同的資料。RTK Query 會自動移除重複要求,因此您不必擔心檢查進行中的要求和效能最佳化。讓我們評估以下沙盒 - 請務必查看瀏覽器開發人員工具中的網路面板。您將看到 3 個要求,即使有 4 個訂閱的元件 - bulbasaur
只會提出一個要求,而且載入狀態會在兩個元件之間同步。為了好玩,請嘗試將下拉式選單的值從 Off
變更為 1s
,看看這種行為是否會在重新執行查詢時繼續。