12
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【React】ReduxToolkitのcreateAsyncThunkで非同期処理を実装する

Last updated at Posted at 2021-05-29

ReduxToolkitでの非同期通信を学習するにあたり、こちらの記事に出会いました。

【React】ReduxToolkitで非同期処理を実装する

Qiitaの記事一覧を取得するという、とても親近感のわく題材でして、解説もとてもわかりやすくオススメの記事です。

createAsyncThunkを使って書き換えてみる

同じ題材で、createAsyncThunkを使ったら、どのようなコードになるのか気になったため、やってみます。

参考記事のサンプルコードをベースにして、Sliceのコードを以下のように書き換えてみます。

src/store/qiitaSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { getItems } from '../api/qiitaApi';

// Thunk
export const fetchItems = createAsyncThunk(
  'fetchItemsThunk',
  async () => getItems()
)

// Slice
export const qiitaSlice = createSlice({
  name: 'qiita',
  // stateの初期値を設定
  initialState: { loading: false, error: null, items: [] },
  reducers: {},
  extraReducers: builder => {
    // 通信を開始した時
    builder.addCase(fetchItems.pending, (state, action) => {
      state.loading = true;
      state.error = null;
    })
    // 通信が失敗した時
    builder.addCase(fetchItems.rejected, (state, action) => {
      state.loading = false;
      state.error = action.error.stack;
    })
    // 通信が成功した時
    builder.addCase(fetchItems.fulfilled, (state, action) => {
      state.loading = false;
      state.error = null;
      state.items = action.payload;
    })
  },
});

// Selectors
export const selectQiita = ({ qiita }) => qiita;

// Reducer(must be default export)
export default qiitaSlice.reducer;

これで、コードの変更は終了です。
以降は解説です。

fetchItemsの変更点

変更前のコードは、Sliceで定義したActionを fetchItems の中でdispatchしています。
変更後のコードは、Sliceで定義したActionは使わず、 createAsyncThunk で包むだけにしました。

変更前

// Actions
export const { fetchStart, fetchFailure, fetchSuccess } = qiitaSlice.actions;

// 外部からはこの関数を呼んでもらう
export const fetchItems = () => async dispatch => {
  try {
    dispatch(fetchStart());
    dispatch(fetchSuccess(await getItems()));
  } catch (error) {
    dispatch(fetchFailure(error.stack));
  }
};

変更後

// 外部からはこの関数を呼んでもらう
export const fetchItems = createAsyncThunk(
    'fetchItemsThunk',
    async () => getItems()
)

Recucerの変更点

createAsyncThunk は以下の3つのActionを生成してくれるので、それを利用しています。

  • pending : 今回はAPI通信開始時に相当
  • rejected : 今回はAPI通信失敗時に相当
  • fulfilled : 今回はAPI通信成功時に相当

これらのActionは、 extraReducersbuilder を利用して追加しています。

変更前

  reducers: {
    // 通信を開始した時に呼ぶ関数
    fetchStart(state, action) { /* 中略 */ },
    // 通信が失敗した時に呼ぶ関数
    fetchFailure(state, action) { /* 中略 */ },
    // 通信が成功した時に呼ぶ関数
    fetchSuccess(state, action) { /* 中略 */ },
  },

変更後

  extraReducers: builder => {
    // 通信を開始した時
    builder.addCase(fetchItems.pending, (state, action) => { /* 中略 */ })
    // 通信が失敗した時
    builder.addCase(fetchItems.rejected, (state, action) => { /* 中略 */ })
    // 通信が成功した時
    builder.addCase(fetchItems.fulfilled, (state, action) => { /* 中略 */ })
  },

rejected の時、 action.payloadundefined ですので、ご注意ください。
代わりに、 action.error が利用できます。

さいごに

本記事作成にあたり、以下の記事を参考にさせていただきました。ありがとうございました。

12
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?