API スライス:エンドポイント
API スライスオブジェクトには、endpoints
フィールドが含まれています。このセクションでは、createApi
に提供したエンドポイント名を、データフェッチのトリガーと、そのエンドポイントのキャッシュされたデータの読み取りに使用されるコアReduxロジック(thunkとセレクター)にマッピングします。React固有のバージョンのcreateApi
を使用している場合、各エンドポイント定義には、そのエンドポイント用に自動生成されたReactフックも含まれます。
各エンドポイント構造には、次のフィールドが含まれています
type EndpointLogic = {
initiate: InitiateRequestThunk
select: CreateCacheSelectorFactory
matchPending: Matcher<PendingAction>
matchFulfilled: Matcher<FulfilledAction>
matchRejected: Matcher<RejectedAction>
}
initiate
シグネチャ
type InitiateRequestThunk = StartQueryActionCreator | StartMutationActionCreator;
type StartQueryActionCreator = (
arg:any,
options?: StartQueryActionCreatorOptions
) => ThunkAction<QueryActionCreatorResult, any, any, UnknownAction>;
type StartMutationActionCreator<D extends MutationDefinition<any, any, any, any>> = (
arg: any
options?: StartMutationActionCreatorOptions
) => ThunkAction<MutationActionCreatorResult<D>, any, any, UnknownAction>;
type SubscriptionOptions = {
/**
* How frequently to automatically re-fetch data (in milliseconds). Defaults to `0` (off).
*/
pollingInterval?: number;
/**
* Defaults to `false`. This setting allows you to control whether RTK Query will try to refetch all subscribed queries after regaining a network connection.
*
* If you specify this option alongside `skip: true`, this **will not be evaluated** until `skip` is false.
*
* Note: requires `setupListeners` to have been called.
*/
refetchOnReconnect?: boolean;
/**
* Defaults to `false`. This setting allows you to control whether RTK Query will try to refetch all subscribed queries after the application window regains focus.
*
* If you specify this option alongside `skip: true`, this **will not be evaluated** until `skip` is false.
*
* Note: requires `setupListeners` to have been called.
*/
refetchOnFocus?: boolean;
};
interface StartQueryActionCreatorOptions {
subscribe?: boolean;
forceRefetch?: boolean | number;
subscriptionOptions?: SubscriptionOptions;
}
interface StartMutationActionCreatorOptions {
/**
* If this mutation should be tracked in the store.
* If you just want to manually trigger this mutation using `dispatch` and don't care about the
* result, state & potential errors being held in store, you can set this to false.
* (defaults to `true`)
*/
track?: boolean;
}
説明
データフェッチクエリまたはミューテーションをトリガーするためにディスパッチできるRedux thunkアクションクリエイター。
React Hooksユーザーは、フックが自動的にこれらのアクションを必要に応じてディスパッチするため、ほとんどの場合、これらを直接使用する必要はありません。
アクションクリエイターをディスパッチする際、その特定のサブスクリプションを更新したい場合に、返されるpromiseへの参照を保存する責任があります。また、コンポーネントがアンマウントされたら、手動でアンサブスクライブする必要があります。それがどのようなものかを理解するために、Svelteの例またはReactクラスコンポーネントの例を参照してください。
例
import { useState } from 'react'
import { useAppDispatch } from './store/hooks'
import { api } from './services/api'
function App() {
const dispatch = useAppDispatch()
const [postId, setPostId] = useState<number>(1)
useEffect(() => {
// Add a subscription
const result = dispatch(api.endpoints.getPost.initiate(postId))
// Return the `unsubscribe` callback to be called in the `useEffect` cleanup step
return result.unsubscribe
}, [dispatch, postId])
return (
<div>
<div>Initiate query example</div>
</div>
)
}
import { useState } from 'react'
import { useAppDispatch } from './store/hooks'
import { api, Post } from './services/api'
function App() {
const dispatch = useAppDispatch()
const [newPost, setNewPost] = useState<Omit<Post, 'id'>>({ name: 'Ash' })
function handleClick() {
// Trigger a mutation
// The `track` property can be set `false` in situations where we aren't
// interested in the result of the mutation
dispatch(api.endpoints.addPost.initiate(newPost), { track: false })
}
return (
<div>
<div>Initiate mutation example</div>
<button onClick={handleClick}>Add post</button>
</div>
)
}
select
シグネチャ
type CreateCacheSelectorFactory =
| QueryResultSelectorFactory
| MutationResultSelectorFactory
type QueryResultSelectorFactory = (
queryArg: QueryArg | SkipToken,
) => (state: RootState) => QueryResultSelectorResult<Definition>
type MutationResultSelectorFactory<
Definition extends MutationDefinition<any, any, any, any>,
RootState,
> = (
requestId: string | SkipToken,
) => (state: RootState) => MutationSubState<Definition> & RequestStatusFlags
type SkipToken = typeof Symbol
説明
キャッシュキー引数を受け取り、指定されたキャッシュキーを使用してこのエンドポイントのキャッシュされたデータを読み取るための新しいメモ化されたセレクターを生成する関数。生成されたセレクターは、ReselectのcreateSelector
を使用してメモ化されます。
クエリではなくミューテーションの結果を選択する場合、関数はリクエストIDを受け取ります。
RTKQは内部的にskipToken
という名前のSymbol
を定義しています。これらのセレクターにクエリ引数としてskipToken
を渡すと、セレクターはデフォルトの初期化されていない状態を返します。これは、特定のクエリが無効になる場合に値を返さないようにするために使用できます。
React Hooksユーザーは、フックが自動的にこれらのセレクターを必要に応じて使用するため、ほとんどの場合、これらを直接使用する必要はありません。
.select(someCacheKey)
を呼び出すたびに、*新しい*セレクター関数インスタンスが返されます。メモ化を正しく機能させるには、キャッシュキーごとにセレクター関数を一度作成し、そのセレクター関数インスタンスを再利用する必要があります。毎回新しいセレクターインスタンスを作成しないでください。
例
import { useState, useMemo } from 'react'
import { useAppDispatch, useAppSelector } from './store/hooks'
import { api } from './services/api'
function App() {
const dispatch = useAppDispatch()
const [postId, setPostId] = useState(1)
// useMemo is used to only call `.select()` when required.
// Each call will create a new selector function instance
const selectPost = useMemo(
() => api.endpoints.getPost.select(postId),
[postId],
)
const { data, isLoading } = useAppSelector(selectPost)
useEffect(() => {
// Add a subscription
const result = dispatch(api.endpoints.getPost.initiate(postId))
// Return the `unsubscribe` callback to be called in the cleanup step
return result.unsubscribe
}, [dispatch, postId])
if (isLoading) return <div>Loading post...</div>
return (
<div>
<div>Initiate query example</div>
<div>Post name: {data.name}</div>
</div>
)
}
import { useState, useMemo } from 'react'
import { skipToken } from '@reduxjs/toolkit/query'
import { useAppDispatch, useAppSelector } from './store/hooks'
import { api } from './services/api'
function App() {
const dispatch = useAppDispatch()
const [newPost, setNewPost] = useState({ name: 'Ash' })
const [requestId, setRequestId] = useState<typeof skipToken | string>(
skipToken,
)
// useMemo is used to only call `.select(..)` when required.
// Each call will create a new selector function instance
const selectMutationResult = useMemo(
() => api.endpoints.addPost.select(requestId),
[requestId],
)
const { isLoading } = useAppSelector(selectMutationResult)
function handleClick() {
// Trigger a mutation
const result = dispatch(api.endpoints.addPost.initiate(newPost))
// store the requestId to select the mutation result elsewhere
setRequestId(result.requestId)
}
if (isLoading) return <div>Adding post...</div>
return (
<div>
<div>Select mutation example</div>
<button onClick={handleClick}>Add post</button>
</div>
)
}
マッチャー
Redux Toolkit アクションマッチングユーティリティのセットで、このthunkによってディスパッチされるpending
、fulfilled
、rejected
アクションにマッチします。これにより、createSlice.extraReducers
やカスタムミドルウェアなど、そのエンドポイントのReduxアクションにマッチできます。それらは次のように実装されています。
matchPending: isAllOf(isPending(thunk), matchesEndpoint(endpoint)),
matchFulfilled: isAllOf(isFulfilled(thunk), matchesEndpoint(endpoint)),
matchRejected: isAllOf(isRejected(thunk), matchesEndpoint(endpoint)),