本文へスキップ

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ユーザーは、フックが自動的にこれらのアクションを必要に応じてディスパッチするため、ほとんどの場合、これらを直接使用する必要はありません。

React Hooks以外でのアクションの使用

アクションクリエイターをディスパッチする際、その特定のサブスクリプションを更新したい場合に、返されるpromiseへの参照を保存する責任があります。また、コンポーネントがアンマウントされたら、手動でアンサブスクライブする必要があります。それがどのようなものかを理解するために、Svelteの例またはReactクラスコンポーネントの例を参照してください。

initiate クエリ例
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>
)
}
initiate ミューテーション例
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)を呼び出すたびに、*新しい*セレクター関数インスタンスが返されます。メモ化を正しく機能させるには、キャッシュキーごとにセレクター関数を一度作成し、そのセレクター関数インスタンスを再利用する必要があります。毎回新しいセレクターインスタンスを作成しないでください。

select クエリ例
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>
)
}
select ミューテーション例
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によってディスパッチされるpendingfulfilledrejectedアクションにマッチします。これにより、createSlice.extraReducersやカスタムミドルウェアなど、そのエンドポイントのReduxアクションにマッチできます。それらは次のように実装されています。

 matchPending: isAllOf(isPending(thunk), matchesEndpoint(endpoint)),
matchFulfilled: isAllOf(isFulfilled(thunk), matchesEndpoint(endpoint)),
matchRejected: isAllOf(isRejected(thunk), matchesEndpoint(endpoint)),