ReduxTookitチーム謹製RTK QueryをReactで試してみた
はじめに
swrやreact-queryなどキャッシュ技術を駆使して状態管理までできるQueryツールが躍進していますが、そんな中、ReduxTookitチーム謹製もキャッシュ機能付きQueryツールが開発中ということなので早速Reactで試してみました。(2021年5月現在β版)
ver1.6.0から正式にtoolkitへ組み込まれました(2021年6月現在)
環境構築
React環境をcreate-react-app
のredux-typescript
テンプレートから作成します。
$ yarn create react-app rtk-query-sample --template redux-typescript
$ cd rtk-query-sample
$ yarn upgrade-interactive --latest
$ yarn start
念の為問題なく起動できることを確認したところで、RTK Queryをインストールします。
$ yarn add @reduxjs/toolkit @rtk-incubator/rtk-query
依存関係を含め下記が追記されました。
ちなみに今回はredux-typescript
テンプレートなので、@reduxjs/toolkit
は最初から1.5.1が入っていました。
"@reduxjs/toolkit": "^1.5.1",
"@rtk-incubator/rtk-query": "^0.3.0",
試してみる
ここからは公式サイトのサンプルに沿ってPokeAPIを使ったRTK Queryの機能を試していこうと思います。
createApiでカスタムフックを作成
RTK QueryではcreateApi
という関数を利用すると指定したエンドポイントからデータを取得するためのカスタムフックを自動生成してくれます。
import { createApi, fetchBaseQuery } from '@rtk-incubator/rtk-query/react';
// 接続先のbaseUrlとパスを設定します
export const pokemonApi = createApi({
reducerPath: 'pokemonApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
endpoints: (builder) => ({
getPokemonByName: builder.query({
query: (name: string) => `pokemon/${name}`,
}),
}),
});
// createApiで定義したendpointsにあわせたhooksを自動生成してくれますので、利用するものをexportします。
// use + endpointsで定義した名称 + Query という名称で作成されるようです。
// 他にuseLazy + endpointsで定義した名称 + Queryも作成されます。
export const { useGetPokemonByNameQuery } = pokemonApi;
swrやreact-queryですと都度エンドポイントの情報やキーを渡すことになると思うのですが、RTK QueryではAPIの定義は一箇所でまとめて行う必要があるようです。このあたりの思想もRedux Toolkitチーム謹製感がありますね。
イメージとしてはApolloClientなどGraphQL系のツールに近い感じを受けました。
Storeを作成
つぎにstore.ts
ファイルに記載を追加します。
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
// setupListenersと先程作成したpokemonApiをimport
import { setupListeners } from '@rtk-incubator/rtk-query/dist';
import { pokemonApi } from '../services/pokemon';
export const store = configureStore({
reducer: {
counter: counterReducer,
// pokemonApiをreducerに追加します
[pokemonApi.reducerPath]: pokemonApi.reducer,
},
// middlewareとしてpokemonApiを追加することで、caching、invalidation、pollingなどRTK Queryの提供する多数の機能が有効になります
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(pokemonApi.middleware),
});
// 追記は任意ですが、refetchOnFocus/refetchOnReconnectという機能を利用するためには下記が必要です
setupListeners(store.dispatch);
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
デベロッパーツールから動作確認
redux-typescript
テンプレートを利用するとすでにProvider
は反映済みのためここで一度起動してReduxデベロッパーツールから状態を確認してみます。
pokemonApiのTreeが表示されました。何やらたくさんあります
ちなみにstore.ts
にsetupListeners(store.dispatch);
を記載している場合は、ページがアクティブになった時、別タブに移動して非アクティブになった際に状態を監視して__rtkq/focused
、__rtkq/unfocused
というアクションが走り、focused
フラグをトグルしてくれるようです。
コンポーネント側の実装
つぎにコンポーネント側からhooksを利用してみます。
App.tsxをまるっと書き換えます。
import React from 'react';
import { useGetPokemonByNameQuery } from './services/pokemon';
import './App.css';
const App: React.VFC = () => {
const { data, error, isLoading } = useGetPokemonByNameQuery('bulbasaur');
return (
<div className="App">
{error ? (
<h1>エラー</h1>
) : isLoading ? (
<h1>Loading...</h1>
) : data ? (
<>
<h1>{data.species.name}</h1>
<img src={data.sprites.front_shiny} alt={data.species.name} />
</>
) : null}
</div>
);
};
export default App;
useGetPokemonByNameQuery
にポケモンの名前を渡すことでその詳細情報を取得することができます。data
には取得情報が、error
にはエラー時のエラー情報が、isLoading
には読み込み時の真偽値が入ってくるので、簡単に状態管理を分岐させることができます。
他にisError
、isFetching
などの真偽値やタイムスタンプなど色々と取得可能です。
起動してみると、createAsyncThunk
と同じようにpending
、fulfilled
とアクションを経由してデータが表示されました。
今回はRTK Queryのスタートガイドにあるほんの触り部分だけを紹介させていただきました。
他にも公式サイトにはサンプルがたくさんありますのでぜひ見てみていただければと思います。
さいごに
XXX Query業界も群雄割拠に突入でしょうか、、RTK Queryはまだ2021年5月現在では0.3betaという状態なのでプロダクトへの利用は難しいのかもしれませんが、すでにReduxToolkitを利用している環境であれば管理もデバッグツールも一元化できるので導入しやすいのではと思います。
引き続き潜入調査を続けます。。。
Discussion