跳至主要内容

[Redux] Redux Toolkit Query

RTK Query Quick Start

  • RTKQ 會自動處理 dedupe 的情況(在同一頁面中有多個元件需要大相同的 API 取得相同的資源時,只會發出一次 request)。
  • 透過 RTK Query 可以不需使用 thunks 或任何 reducers 來管理 data fetching 的資料

檔案管理

  • RTK Query 和 SWRreact-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 方法
  • 如果要使用 refetchOnFocusrefetchOnReconnect 的方法,才需要加上 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;