RTK クエリ概要
- RTK クエリとは何か、そしてどのような問題を解決するか
- RTK クエリに含まれるAPI
- RTK クエリの基本的な使用方法
RTK クエリは、強力なデータ取得およびキャッシュツールです。Webアプリケーションでのデータ読み込みの一般的なケースを簡素化するために設計されており、データ取得とキャッシュロジックを手動で記述する必要がなくなります。
RTK クエリは、Redux Toolkitパッケージに含まれるオプションのアドオンであり、その機能はRedux Toolkitの他のAPIの上に構築されています。
RTK クエリの使用方法については、Reduxコアドキュメントサイトの完全な"Redux Essentials"チュートリアルを参照してください。
ビデオコースを希望する場合は、RTK クエリの作成者であるLenz Weber-TronicによるEggheadで無料視聴できるこのRTK クエリビデオコースを視聴するか、最初のレッスンをご覧ください。
動機
Webアプリケーションは通常、表示するためにサーバーからデータを取得する必要があります。また、通常は、そのデータの更新を行い、それらの更新をサーバーに送信し、クライアント上のキャッシュされたデータをサーバー上のデータと同期させる必要があります。これは、今日のアプリケーションで使用されている他の動作を実装する必要があるため、さらに複雑になります。
- UIスピナーを表示するために読み込み状態を追跡する
- 同じデータに対する重複したリクエストを避ける
- UIをより高速にするための楽観的更新
- ユーザーがUIと対話する際のキャッシュの有効期間の管理
Reduxコアは常に非常に最小限のものでした。実際のロジックをすべて記述するのは開発者の責任です。つまり、Reduxには、これらのユースケースを解決するのに役立つ組み込みのものは何も含まれていませんでした。Reduxのドキュメントでは、読み込み状態とリクエストの結果を追跡するためのリクエストライフサイクルの周りのアクションをディスパッチする一般的なパターンについて説明しており、Redux ToolkitのcreateAsyncThunk
APIはその典型的なパターンを抽象化するように設計されていました。しかし、ユーザーは読み込み状態とキャッシュされたデータを管理するために、依然としてかなりの量のReducerロジックを記述する必要があります。
ここ数年で、Reactコミュニティは、「データの取得とキャッシュ」は「状態管理」とは本当に異なる懸念事項であることに気づきました。Reduxのような状態管理ライブラリを使用してデータをキャッシュできますが、ユースケースは十分に異なっているため、データ取得のユースケースのために特別に構築されたツールを使用する価値があります。
RTK クエリは、Apollo Client、React Query、Urql、SWRなど、データ取得のソリューションを開拓してきた他のツールからヒントを得ていますが、そのAPI設計に独自のアプローチを加えています。
- データ取得とキャッシュのロジックは、Redux Toolkitの
createSlice
とcreateAsyncThunk
APIの上に構築されています。 - Redux ToolkitはUIに依存しないため、RTK クエリの機能は任意のUIレイヤーで使用できます。
- APIエンドポイントは、引数からクエリパラメータを生成する方法や、キャッシングのために応答を変換する方法を含め、事前に定義されています。
- RTK クエリは、データ取得プロセス全体をカプセル化し、コンポーネントに
data
とisLoading
フィールドを提供し、コンポーネントのマウントとアンマウントに伴うキャッシュデータの寿命を管理するReactフックも生成できます。 - RTK クエリは、「キャッシュエントリライフサイクル」オプションを提供しており、初期データの取得後にWebsocketメッセージを介してストリーミングキャッシュ更新などのユースケースを有効にします。
- OpenAPIとGraphQLスキーマからのAPIスライスのコード生成に関する初期の作業例があります。
- 最後に、RTK クエリは完全にTypeScriptで記述されており、優れたTS使用エクスペリエンスを提供するように設計されています。
含まれるもの
API
RTK クエリは、コアRedux Toolkitパッケージのインストールに含まれています。以下の2つのエントリポイントのいずれかから使用できます。
import { createApi } from '@reduxjs/toolkit/query'
/* React-specific entry point that automatically generates
hooks corresponding to the defined endpoints */
import { createApi } from '@reduxjs/toolkit/query/react'
RTK クエリには、次のAPIが含まれています。
createApi()
:RTK クエリの機能の中核です。バックエンドAPIやその他の非同期ソースからデータを取得する方法を記述する「エンドポイント」のセットを定義できます。これには、そのデータの取得と変換方法の設定も含まれます。ほとんどの場合、これはアプリごとに一度使用し、「ベースURLごとに1つのAPIスライス」というルールに従う必要があります。fetchBaseQuery()
:fetch
をラップした小さなラッパーで、リクエストを簡素化することを目的としています。ほとんどのユーザーがcreateApi
で使用する推奨されるbaseQuery
として意図されています。<ApiProvider />
:Reduxストアがない場合、Provider
として使用できます。setupListeners()
:refetchOnMount
とrefetchOnReconnect
の動作を有効にするために使用されるユーティリティです。
バンドルサイズ
RTK クエリは、アプリのバンドルサイズに固定の1回限りの量を追加します。RTK クエリはRedux ToolkitとReact-Reduxの上に構築されているため、追加されるサイズは、アプリで既にそれらを使用しているかどうかに応じて異なります。推定されるmin+gzipバンドルサイズは次のとおりです。
- 既にRTKを使用している場合:RTK クエリで約9KB、フックで約2KB。
- まだRTKを使用していない場合
- Reactなし:RTK+依存関係+RTK クエリで17KB
- Reactあり:19KB + React-Redux(ピア依存関係)
追加のエンドポイント定義を追加しても、endpoints
定義内の実際のコードに基づいてサイズが増加するだけであり、通常は数バイトだけです。
RTK クエリに含まれる機能は、追加されたバンドルサイズをすぐに相殺し、手書きのデータ取得ロジックの排除は、ほとんどの意味のあるアプリケーションでサイズを改善するはずです。
基本的な使用方法
APIスライスの作成
RTK クエリは、コアRedux Toolkitパッケージのインストールに含まれています。以下の2つのエントリポイントのいずれかから使用できます。
import { createApi } from '@reduxjs/toolkit/query'
/* React-specific entry point that automatically generates
hooks corresponding to the defined endpoints */
import { createApi } from '@reduxjs/toolkit/query/react'
Reactでの一般的な使用方法では、まずcreateApi
をインポートし、「APIスライス」を定義して、サーバーのベースURLと対話するエンドポイントをリストします。
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
ストアの設定
「APIスライス」には、自動生成されたReduxスライスReducerと、サブスクリプションのライフタイムを管理するカスタムミドルウェアも含まれています。これらはどちらもReduxストアに追加する必要があります。
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)
コンポーネントでのフックの使用
最後に、APIスライスから自動生成されたReactフックをコンポーネントファイルにインポートし、必要なパラメータを使用してコンポーネントでフックを呼び出します。RTK クエリは、マウント時に自動的にデータを取得し、パラメータが変更されたときに再取得し、結果に{data, isFetching}
値を提供し、それらの値が変更されるとコンポーネントを再レンダリングします。
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')
// render UI based on data and loading state
}
詳細情報
RTK クエリ クイックスタートチュートリアルでは、Redux Toolkitを使用するプロジェクトにRTK クエリを追加する方法、エンドポイント定義を使用して「APIスライス」を設定する方法、コンポーネントで自動生成されたReactフックを使用する方法の例を示しています。
RTK クエリ使用方法ガイドセクションには、データのクエリ、サーバーへの更新を送信するためのmutationsの使用、ストリーミングキャッシュ更新などに関する情報が含まれています。
例ページには、GraphQLを使用したクエリの実行、認証、さらにはSvelteなどの他のUIライブラリでのRTK クエリの使用といったトピックを示す実行可能なCodeSandboxesが含まれています。