Redux-Thunkで非同期処理ができる仕組みを理解しよう

#目次
- [概要](#概要)
- [Redux-Thunkとは](#redux-thunkとは)
- [Redux-Thunkのフロー](#redux-thunkのフロー)
- [Redux-Thunkの使用](#redux-thunkの使用)
- [まとめ](#まとめ)


#概要
この記事では、Reduxで非同期処理を行わせるためのミドルウェア**Redux-Thunk**についてまとめています。私はRedux-Thunkについて初めて学んだとき、仕組みなどがよくわかりませんでした。この記事が私と同じような境遇の方の手助けとなるようであれば幸いです。
なお、Reduxに関しては[こちらの記事](https://qiita.com/jima-r20/items/4a5d0074e24add0df3fc)にまとめていますので、合わせて参考にしてみてください。

###環境

| 導入          | version  |
|:------------ |---------:|
| react        | 16.13.1  |
| react-redux  | 7.2.0    |
| redux        | 4.0.5    |
| redux-thunk  | 2.3.0    |
| axios        | 0.19.2   |


#Redux-Thunkとは
**Redux-Thunk**とは、ReduxのAction Creatorに**非同期処理**を実装するためのミドルウェアです。

###何ができるの？
Reduxにおける最も一般的なミドルウェアの使い方は非同期Actionの処理です。

Reduxでは基本的に、`Action Creator`によって生成された`Action`を`Store`にディスパッチすることで単純な同期更新を行っています。そこにRedux-Thunkのようなミドルウェアを導入することでStoreの機能を拡張し、非同期ロジックを記述できるようにできます。

通常Action CreatorはActionオブジェクトを返しますが、Redux-Thunkを使用すると**「Thunk」という関数を返すことができる**ようになります。これによってActionのディスパッチを遅らせたり、特定の条件が満たされた場合のみディスパッチできるようになります。

###なぜミドルウェアを使うの？
Action Creatorが**Thunk**を返すことで、`Action Creator`や`Action`、Reactの`Component`に直接的な副作用を引き起こさないようにすることができます。ピュアでない部分はThunkが含んでおり、ミドルウェアがThunkを呼び出して処理を行うことで、アプリケーションの他の部分は比較的ピュアなままにすることができます。このようにすることで、**テスト、保守、拡張性、再利用性を維持することができます**。


#Redux-Thunkのフロー
###Reduxサイクル
Reduxにミドルウェアを導入すると、Reduxサイクルは以下の図のようになります。
ミドルウェアは`Action`が`Reducer`にディスパッチされる前の行程で働きます。
![redux_cycle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622836/5ff82826-091e-7463-6da3-db3e0b90366c.png)


###Redux-Thunkの内部処理
言葉では簡単に説明しましたが、具体的にRedux-Thunk内ではどのような処理を行なっているのかイメージがつかないかと思いますので、図としてまとめてみました。
![flow_of_redux_thunk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622836/918ff32e-5e77-6ecc-bc15-d2ecb456544e.png)

図のようにRedux-Thunkでは、`Action Creator`によって生成された`Action`が関数かどうかを判定しその後の処理を決定します。

**Actionが「オブジェクト」の場合**

- そのまま`Action`を`Reducer`に渡す。

**Actionが「関数」の場合**

- その関数に引数として`dispatch`関数（と`getState`関数）を渡す。
- 「APIリクエストからのレスポンスが返ってくるまで」などの特定の条件が満たされるまで待機する。
- 条件を満たした時にActionをディスパッチする。
- 新たに生成されたActionをRedux-Thunkに再びディスパッチし、Actionがオブジェクトか関数かを判定する。


#Redux-Thunkの使用
では実際の導入方法をみてみましょう。

```react:App.js
import { createStore, applyMiddleware } from `redux`;
import thunk from 'redux-thunk';
import reducers from './reducers';  // reducerを別フォルダに格納している場合を想定しています
// その他のimport文は省略

const store = createStore(reducers, applyMiddleware(thunk));  // ここが重要
```

```react:actions/index.js
// Action Creator
import axios from 'axios';

export const fetchUsers = () => (dispatch) => {
  const response = axios.get('/api/users');

  dispatch({ type: 'FETCH_USERS', payload: response.data });
};
```
以上のように、主に記述するのは`App.js`のような最上位にあるファイルと`actions/index.js`のような`Action creator`が記述されているファイルです。
このようにすることでReduxにRedux-Thunkを適用することができます。

#まとめ
かなりざっくりとした内容になってしまいましたが、基本的な部分については説明できたと思います。
では簡単にこの記事の内容をまとめたいと思います。

- **Redux-Thunkとは**
 - ReduxのAction Creatorに**非同期処理**を実装するためのミドルウェア
 - Action CreatorはActionとしてオブジェクト以外に**関数**も返すことができるようになる
- **なぜミドルウェアを使うのか？**
 - ミドルウェアで処理をする**Thunk**以外をピュアなものにすることができる
 - テスト、保守、拡張、再利用が簡単にできるようになる

さらに詳しく知りたい方は以下の参考資料を見ていただければと思います。


#参考資料
- [ReduxThunk(GitHub)](https://github.com/reduxjs/redux-thunk)
- [Redux-thunkを使ったReduxの非同期処理](https://kde.hateblo.jp/entry/2019/02/14/220155#:~:text=Redux%2Dthunk%E3%81%A8%E3%81%AF&text=%E9%96%A2%E6%95%B0%E3%82%92%E8%BF%94%E3%81%99%20Action%20creator,%E3%81%97%E3%81%A6%E3%82%82%E5%95%8F%E9%A1%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82)
- [Why do we need middleware for async flow in Redux?](https://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux/34599594#34599594)
- [Thunks in Redux: The Basics](https://medium.com/fullstack-academy/thunks-in-redux-the-basics-85e538a3fe60)
- [What the heck is a 'thunk'?](https://daveceddia.com/what-is-a-thunk/)
- [redux-thunk入門、簡単まとめ](https://qiita.com/hiroya8649/items/c202742c99d2cc6159b8)
- [本とプログラミングと時々ミニブタ redux-thunkを用いて非同期処理を行う Part3](https://pigblog.org/redux-thunk-3)