0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

こんにちは。Naotoです。

今回は、Redux Thunkを使ってReduxで非同期処理(その他副作用処理)を扱う方法について説明したいと思います。

※この記事では、TypeScript, Redux Toolkitを使用します。

前提知識

  • Reactの基礎知識
  • Reduxの基礎知識

学んだきっかけ

個人開発中のタスク管理アプリの実装中、「初期レンダリング時に、APIを叩いてデータベースからタスクやカテゴリなどの情報を取得し、ReduxのStateに反映させる」といったコードを書いていました。

最初に思いついた方法は、トップページのuseEffect内に非同期処理を直接書き、その後、取得した値をReduxのStateにdispatchする方法です。

コードは以下です。

useEffect(() => {
  (async () => {
    // 未完了タスク取得
    const inCompletedTaskItems: TaskItem[] = await taskApi.inCompletedTaskGet(userId);
    // 取得した未完了タスクを未完了タスクStateに反映
    inCompletedTaskItems.forEach((inCompletedTaskItem) =>
      dispatch(inCompletedTaskAdd(inCompletedTaskItem))
    );

    // 完了タスク取得
    const completedTaskItems: TaskItem[] = await taskApi.completedTaskGet(userId);
    // 取得した完了タスクを完了タスクStateに反映
    completedTaskItems.forEach((completedTaskItem) =>
      dispatch(completedTaskAdd(completedTaskItem))
    );

    // カテゴリ取得
    const categories: Category[] = await taskApi.categoryGetAll(userId);
    // 取得したカテゴリをカテゴリStateに反映
    categories.forEach((category) => dispatch(categoryAdd(category)));

    // スケジュール取得
    const schedules: Schedule[] = await taskApi.scheduleGetAll(userId);
    // 取得したスケジュールをスケジュールStateに反映
    schedules.forEach((schedule) => dispatch(scheduleAdd(schedule)));
  })();
}, []);

やっていることは単純ですが、ものすごくコードが長くなってしまいます。
そこで、他に何か良い方法が無いか調査したところ、今回紹介する、Redux Thunkに辿り着きました。

Redux Thunkとは?

Redux Thunkとは、タイトルの通り、Reduxで非同期処理を扱えるようにするものです。

通常、Reduxを使ってアプリケーションの状態管理を行う際、Stateを更新するためには、Reducerに更新処理を記述します。しかし、Reducerは純粋関数でないといけないといったルールがあります。


※純粋関数 :以下の性質を持つ関数

  • returnが引数のみに依存する。
  • その関数外に影響を与えない。(参照・変更しない。)

そのため、「Reducer内でAPIを叩いて、Stateの更新と同時にデータベースを更新する」といったことはできません。

しかしRedux Thunkを使うことで、
非同期処理をはじめとする、DOM操作、コンソールへのログ出力、タイマー処理といった、いわゆる「副作用」をReduxで扱えるようになります。

(Redux Thunkを用いて記述した副作用は、ReducerではなくMiddlewareという部分で扱われます。)

Redux Thunkを使用したコード

Redux Thunk関数の定義

基本形は以下になります。

以下、reduxThunkFnが実行されると、payloadとして引数を受け取り、同時にdispatch関数、getState関数を引数とする関数が生成されreturnされます。
そして、returnされる関数内で、副作用の処理を行うことができます。

const reduxThunkFn = (payload) => {
    return (dispatch, getState) => {
        副作用処理
    }
}

では、今回は、未完了タスクをAPIから取得し、ReduxのStateに反映する場合について説明します。

以下は、未完了タスクのSlicerにRedux Thunk関数を定義した例です。

import { TaskItem } from "../@types";
import { Dispatch, createSlice } from "@reduxjs/toolkit";
import taskApi from "../api/task";

// 未完了タスクState////////////////////////////////////////////////////////////////////

// 初期値
const initialState: TaskItem[] = [];

// Slice作成
export const inCompletedTaskItemsSlice = createSlice({
  name: "inCompletedTaskItems",
  initialState,
  reducers: {
    // タスク追加
    inCompletedTaskAdd: (state, action) => {
      state.push(action.payload);
    },
  },
});

// ここでRedux Thunk関数を定義(TypeScriptを使用しているため、型情報を追記しています。)
const getAllInCompletedTaskItems = (payload: string) => {
  return async (dispatch: Dispatch, getState: () => TaskItem) => {
    // ここで、APIを叩きデータベースから未完了タスクを取得しています。(副作用処理)
    const inCompletedTaskItems: TaskItem[] = await taskApi.inCompletedTaskGet(payload);
    // 引数のdispatch関数を使用し、取得した未完了タスクをStateに反映
    inCompletedTaskItems.forEach((inCompletedTaskItem) =>
      dispatch(inCompletedTaskAdd(inCompletedTaskItem))
    );
  };
};

// Redux Thunk関数をexport
export { getAllInCompletedTaskItems };

export default inCompletedTaskItemsSlice.reducer;

上記により、データベースからのデータ取得とReduxのState更新を同時に行える、getAllInCompletedTaskItems関数が完成し、他コンポーネントから使用可能となりました。

同じように、完了タスク、カテゴリー、スケジュールのSliceにもRedux Thunk関数を定義します。(コードは割愛)

Redux Thunk関数の使用

上記でexportしたそれぞれのRedux Thunk関数をトップページのuseEffect内で呼び出します。

useEffect(() => {
  (async () => {
    // APIから未完了タスクを取得&Stateに反映
    dispatch(getAllInCompletedTaskItems(userId));

    // APIから完了タスクを取得&Stateに反映
    dispatch(getAllCompletedTaskItems(userId));

    // APIからカテゴリを取得&Stateに反映
    dispatch(getAllCategories(userId));

    // APIからスケジュールを取得&Stateに反映
    dispatch(getAllSchedules(userId));
  })();
}, []);

コードが冒頭のコードと比べてとても簡潔になりました。

まとめ

このように、Redux Thunkを使用することで、非同期処理をReduxのアクションとして管理し、コードを整理することができます。

ぜひ、皆さんもRedux Thunkを活用して、Reduxでの非同期処理を効率化してみてください!!!

最後までお読みいただきありがとうございました!


ps. 週2投稿を目指していますが、最近週1が限界です。。。頑張ります。。。。
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?