モチベーション
Redux Toolkitを使っている中で良く見かけるこいつが何者かよく理解しないまま何となくで使ってしまっていたので、自分の知識の整理も含めてアウトプットすることにしました
createAsyncThunkってなに?
一言でまとめると、「非同期処理の実行状況に応じたActionCreatorを生成する関数」
Promiseの状況(pending, fulfilled, reject)に応じたActionCreatorを生成してくれる
createAsyncThunkの使い方
-
どんな値を引数に渡すのか?
- 第一引数(typePrefix)
- ActionTypeのprefixとして利用される文字列
- 型:
string
- 第二引数(payloadCreator)
- Promiseを返す非同期処理の関数(async関数)
- 型:
AsyncThunkPayloadCreator<Returned, ThunkArg, ThunkApiConfig>
- 第三引数(options)
- Thunk API
- ここはoptional
- 型:
AsyncThunkOptions<ThunkArg, ThunkApiConfig>
- 第一引数(typePrefix)
-
型定義
createAsyncTunk<Returned, ThunkArg = void, ThunkApiConfig extends AsyncThunkConfig = {}>
型定義ややこしい、、
Returned
Genericで定義しているReturned
は、第二引数に渡しているpayloadCreator
に渡されている
中身を覗いてみると、
type AsyncThunkPayloadCreator<
Returned,
ThunkArg = void,
ThunkApiConfig extends AsyncThunkConfig = {}
> = (arg: ThunkArg, thunkAPI: GetThunkAPI<ThunkApiConfig>)
=> AsyncThunkPayloadCreatorReturnValue<Returned, ThunkApiConfig>
Returned
はさらにAsyncThunkPayloadCreatorReturnValue
に渡っている
type AsyncThunkPayloadCreatorReturnValue<
Returned,
ThunkApiConfig extends AsyncThunkConfig
> = Promise<
Returned |
RejectWithValue<GetRejectValue<ThunkApiConfig>>> |
Returned |
RejectWithValue<GetRejectValue<ThunkApiConfig>
>;
Returned
はPromoseの中に入っている
つまり、Returned
は、AsyncThunkPayloadCreator
が返しているAsyncThunkPayloadCreatorReturnValue
の型になっている
→AsyncThunkPayloadCreator
はcreateAsyncThunkの第2引数
→Returned
はcreateAsyncThunk
の第2引数の関数の返り値になっているので、fetchしてくるデータの返り値の型を定義してあげれば良い
ThunkArg
こいつもAsyncThunkPayloadCreator
に渡されている
AsyncThunkPayloadCreator
を再度覗くと、第一引数に渡されていることがわかる
type AsyncThunkPayloadCreator<
Returned,
ThunkArg = void,
ThunkApiConfig extends AsyncThunkConfig = {}
> = (arg: ThunkArg, thunkAPI: GetThunkAPI<ThunkApiConfig>)
=> AsyncThunkPayloadCreatorReturnValue<Returned, ThunkApiConfig>
→createAsyncThunk
の第二引数の第一引数になっている(ややこしい、、)
ThunkApiConfig
Redux ToolkitのThunk APIの型をまとめたもの
AsyncThunkConfig
を継承しているので、AsyncThunkConfig
を見る
type AsyncThunkConfig = {
state?: unknown;
dispatch?: Dispatch;
extra?: unknown;
rejectValue?: unknown;
serializedErrorType?: unknown;
};
どこで使われているかを見ると、こいつもAsyncThunkPayloadCreator
に渡されている
もう一つ深く追っていくと、AsyncThunkPayloadCreator
の第二引数として渡されている
つまり、createAsyncThunk
の第二引数の第二引数になっている(ややこしい、、)
実際にどう使うか?
冒頭でも述べているように、createAsyncThunk
はActionCreatorを作成するので、createAsyncThunk
を使った関数で作られるオブジェクトには、pending
,fulfilled
,reject
が含まれる
const hoge = createAsyncThunk(省略)
// ↓のように参照できるようになる
hoge.pending
hoge.fulfilled
hoge.reject
実際に使ってみる
interface Request {
name: string;
age: number;
}
const hoge = createAsyncTunk<{}, Request, AsyncThunkConfig>(
'type/prefix',
async (request: Request, thunkApi) => {
try {
const res = await axios.get('api/path')
} catch(error) {
return thunkApi.rejectWithValue({ message: error.response.data.errors.join('\n') });
}
)
const slice = createSlice({
name: 'hoge',
initialState: initState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(hoge.pending, (state) => {
// 更新させたいstate書く
// fulfilledとrejectedには、action.payloadに非同期処理の結果の値を入れることができる
state.name = action.payload.name
state.submitting = true
});
builder.addCase(hoge.fulfilled, (state) => {
// 更新させたいstate書く
state.submitting = false
});
builder.addCase(hoge.rejected, (state, action) => {
if (action.payload) {
state.errorMessage = action.payload.message;
}
state.isSubmitting = false;
});
},
});