[Redux] Redux Toolkit Query
- RTK Query Quick Start @ Redux Toolkit > Tutorials > RTK Query Quick Start
- RTK Query Overview @ Redux Toolkit > RTK Query
RTK Query Quick Start
- RTKQ 會自動處理 dedupe 的情況(在同一頁面中有多個元件需要大相同的 API 取得相同的資源時,只會發出一次 request)。
- 透過 RTK Query 可以不需使用 thunks 或任何 reducers 來管理 data fetching 的資料
檔案管理
- RTK Query 和 SWR 或 react-query 有一個比較大的差異在於,RTK Query 會把 API 的定義放在同一個地方管理,而不是在不同元件中有多個 custom hooks,開發團隊認為集中管理 API 定義檔的方式更容易追蹤 request、cache invalidation 等等。
- 一般來說,每一個 baseURL 都只應該有一個 API slice,例如,如果會需要取得
/api/posts
和/api/users
的資料,則它們應該是在同一個 API slice 中,有相同的 baseURL/api/
,和不同的 endpoint。 - 實務上,因為 endpoint 常常非常多,為了維護上的考量,可以參考使用 RTK Query 中的 Code Splitting,以達到可以拆分多個 endpoint 到不同檔案,但仍然維持在同一個 API slice 中
1. Create an API service(src/services/pokemon.ts
)
- 使用
createApi
可以建立 API service,在createApi
中提供了 reducer、middleware、custom hooks 等可以使用
// src/services/pokemon.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
// 透過 createApi 可以建立 RTK query 的 API service,取名為 pokemonApi
export const pokemonApi = createApi({
reducerPath: 'pokemonApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
endpoints: (builder) => ({
getPokemonByName: builder.query({
query: (name) => `pokemon/${name}`,
}),
}),
});
// pokemonApi 會帶有 useGetPokemonByNameQuery 的方法,可以直接呼叫
export const { useGetPokemonByNameQuery } = pokemonApi;
2. Add the service to your store (src/app/store.ts
)
- 每一個 RTKQ service 都會產生一個 slice reducer,需要把它放入 store 中,同時需要加入 middleware 來啟用 RTKQ 提供的 data fetching 方法
- 如果要使用
refetchOnFocus
或refetchOnReconnect
的方法,才需要加上setupListeners
// src/app.store.ts
//...
import { setupListeners } from '@reduxjs/toolkit/query';
import { pokemonApi } from '../services/pokemon';
// 透過 configureStore() 建立 Redux Store
export const store = configureStore({
reducer: {
[pokemonApi.reducerPath]: pokemonApi.reducer,
counter: counterReducer,
},
// 加入 api middleware 來啟用 caching、invalidation、polling 等其他方法
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);
// ...
3. 在元件中使用 RTK Query
- 使用
useGetPokemonByNameQuery
來 query 資料,它會回傳的可參考 API 文件
/* eslint-disable no-nested-ternary */
import { useGetPokemonByNameQuery } from '../../services/pokemon';
const Pokemon = () => {
// const resp = pokemonApi.endpoints.getPokemonByName.useQuery('bulbasaur')
const resp = useGetPokemonByNameQuery('bulbasaur');
const { isLoading, data, error } = resp;
return ({/* ... */);
};
export default Pokemon;