ReduxTookitチーム謹製RTK QueryをReactで試してみた

5 min read読了の目安(約4600字

はじめに

swrやreact-queryなどキャッシュ技術を駆使して状態管理までできるQueryツールが躍進していますが、そんな中、ReduxTookitチーム謹製もキャッシュ機能付きQueryツールが開発中ということなので早速Reactで試してみました。(2021年5月現在β版)

ver1.6.0から正式にtoolkitへ組み込まれました(2021年6月現在)

https://rtk-query-docs.netlify.app/

環境構築

React環境をcreate-react-appredux-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が入っていました。

package.json
"@reduxjs/toolkit": "^1.5.1",
"@rtk-incubator/rtk-query": "^0.3.0",

試してみる

ここからは公式サイトのサンプルに沿ってPokeAPIを使ったRTK Queryの機能を試していこうと思います。

createApiでカスタムフックを作成

RTK QueryではcreateApiという関数を利用すると指定したエンドポイントからデータを取得するためのカスタムフックを自動生成してくれます。

src/services/pokemon.ts
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ファイルに記載を追加します。

src/app/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.tssetupListeners(store.dispatch);を記載している場合は、ページがアクティブになった時、別タブに移動して非アクティブになった際に状態を監視して__rtkq/focused__rtkq/unfocusedというアクションが走り、focusedフラグをトグルしてくれるようです。

コンポーネント側の実装

つぎにコンポーネント側からhooksを利用してみます。
App.tsxをまるっと書き換えます。

src/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には読み込み時の真偽値が入ってくるので、簡単に状態管理を分岐させることができます。
他にisErrorisFetchingなどの真偽値やタイムスタンプなど色々と取得可能です。

起動してみると、createAsyncThunkと同じようにpendingfulfilledとアクションを経由してデータが表示されました。

今回はRTK Queryのスタートガイドにあるほんの触り部分だけを紹介させていただきました。
他にも公式サイトにはサンプルがたくさんありますのでぜひ見てみていただければと思います。

https://rtk-query-docs.netlify.app/

さいごに

XXX Query業界も群雄割拠に突入でしょうか、、RTK Queryはまだ2021年5月現在では0.3betaという状態なのでプロダクトへの利用は難しいのかもしれませんが、すでにReduxToolkitを利用している環境であれば管理もデバッグツールも一元化できるので導入しやすいのではと思います。

引き続き潜入調査を続けます。。。