Reduxの簡単なコードを書きながら、処理の流れを整理してみた

## はじめに

Reduxを最初に勉強する際に、まず登場する用語が、多くて、良く分からんとなりがちだと思います。少なくとも自分はそうです(泣)

まだまだ勉強中ではあるものの、一旦、整理する意味で、Reduxの処理の流れを言語化してみたいと思い、記事にまとめました。

※今は、Redux Toolkitを使うのが普通なのかもしれませんが、そこには触れていません。Redux Toolkitに関しては、追ってアウトプットしようと思っています。

## Reduxを使用する中で登場する用語の整理
まず登場する用語の整理から...  
__State__ 
アプリケーションの状態。

__Store__ 
Stateの状態を保持している場所。

__Action__ 
ユーザーがアプリケーションで何をしたいかという情報を持つプレーンなオブジェクト。
コンポーネントから発行されたActionは、Dispatcherによって、Reducerに渡す。

__Reducer__
Actionを元にStateを更新する副作用の無いメソッド。



## Reduxの処理の流れ
整理する意味でも図化してみました。
① コンポーネントが、Action Creatorを呼び出し、Actionを取得します。
② 取得したActionをReducerに渡します。これを`dispatch`といいます。
③ Reducerは渡されたActionに応じてStateを更新します。
④ コンポーネントは、Stateに変更があった場合は、該当のUIを描画し直します。

何だか、手続きが、面倒くさいように感じますが、そこがポイントです。
決まった手続きでしか変更を加えられない、状態に対して定義された変更しか加えられないルールは、予期せぬ更新処理を防ぎ、コードを予測しやすくしてくれます。

Action Creatorも重要な役割を果たしています。Reducerに対しては決められた属性、値を持つActionを渡さなければいけないのですが、間違ったActionを渡さないよう、Action Creatorを介して、Actionを取得するようにします。


![reduxFlow](//images.ctfassets.net/gtzwy9itrek0/7pI4XGAOyG7l5JC4tIaCYI/288225db8ef2631329add49c92efcf91/Reduxflow.png)

では、実際にそれぞれの役割で書かれる処理を書いてみましょう。
よくあるカウンターですが、何となくイメージの手助けになれば、と思います。


## ユーザーがアプリケーション上で何らかの操作をし、Actionが発行される

ユーザーの操作によって、コンポーネントから、Actionが生成されます。
後述しますが、コンポーネント上で、この定義ファイルをimportして利用することで、コンポーネントからActionの作成依頼をかけられます。

Actionというディレクトリを切って、そこにActionを発行するメソッドを定義しておきます。
以下は __Action Creator__ と呼ばれるものです。dispatchする時に生の値を渡すのでなく、Action Createrの関数の戻り値を使います。これは、バグを防ぐために有効です。

[Redux StyleGuide](https://redux.js.org/style-guide/style-guide/#use-action-creators)


```jsx
//Actionはどんなイベントが起こったかを表現するプレーンなオブジェクトです

export const increment = () => {
  return {
    type: "INCREMENT"
  }
}

export const decrement = () => {
  return {
    type: "DECREMENT"
  }
}
```

actionをdispatchする際は、生の値を渡すのでなく、Action Creatorの戻り値を使う方が安全です。
※以下のように、生の値を渡さないこと。

```jsx
<button onClick={()=> dispatch({type: "INCREMENT"})}>click</button>
<button onClick={()=> dispatch({type: "DECREMENT"})}>click</button>
```

以下のように、Action Creator関数の戻り値を使いましょう。 

```jsx
<button onClick={()=> dispatch(increment())}>click</button>
<button onClick={()=> dispatch(decrement())}>click</button>
```

## 発行されたactionをdispatchする

Actionは生成しただけだと意味がなくて、Dispatchしないと、Store内の値を変更することはできません。
コンポーネント内で、Actionをimportして、ActionをDispatchしましょう。

※Classコンポーネントが主流だった時代は、connect関数が利用されていたようですが、現在は、``useSelector``と``useDispatch``を使って、ReactとReduxの接続が可能なので、こちらを積極的に使っていった方が良さそう。

↓useSelectorを使って、Storeからstate(値)を取得し、useDispatchにAction Creatorを渡して、ActionをDispatchします。

```jsx

import React from 'react';
import { increment, decrement } from 'Action/actionCreator';
import { useSelector, useDispatch } from 'react-redux';

function App() {

  const count = useSelector(state => state.count);
  const dispatch = useDispatch()

  return(
    <>
    <div>{count}</div>
    <button onClick={()=> dispatch(increment())}>click</button>
    <button onClick={()=> dispatch(decrement())}>click</button>
    </>
  )
}

export default App;
```

## DispatchされたActionによってReducerでStateを更新する

ここでは、Reducerディレクトリを切って、reducer.jsに以下の記述を書いています。
Reducerの関数は二つ引数をとります。第一引数にstate、第二引数にはactionがreturnした値をとります。
(ここでは、単純な処理しか書いてませんが、typeとpayloadを書けます)

第一引数のstateですが、基本的には現在の引数の状態を受け取るようになっていますが、もし現在のstateの状態が指定されていない場合は、デフォルトの値をstateの引数に持たせるようにします。

```jsx
export const initialState = { count: 0 };

export const countReducer = (state = initialState.count, action) => {
  switch(action.type) {
    case 'INCREMENT':
      return {
        ...state, count: state.count + 1
      };
    case 'DECREMENT':
      return {
        ...state, count: state.count - 1
      }
    default: {
      return state;
    } 
  }
}
```

## Storeを作成してpropsとして渡す

Reducerが作成できたら、Reduxの核となるStoreを初期化して、Propsとして渡しましょう。
Storeは１アプリケーションにつき、一つです。引数には、reducerと初期値を渡します。

```jsx
const store = createStore(reducer, initialState);
```

最後にStoreを最上位のコンポーネントでProviderを使って、Storeをpropsとして渡します。これで初めて、子孫コンポーネントの中でReduxの機能が使えるようになります。

```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { initialState, reducer } from './Reducer/reducer';

const store = createStore(reducer, initialState);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
```

## まとめ
以上で一通りのReduxに必要な処理が揃ったことになります。上述の`useSelector`と`useDispatch`によって、ReactとReduxの接続は実現できています。ユーザーのアクション(ボタンのクリックなど)の応答として、更新された値が表示されます。

まだまだ理解の浅い部分が沢山ありますが、Reduxのディレクトリ構成(Ducks,re-ducks等)や、もっとすっきり書ける方法(redux toolkit)もキャッチアップして理解を深めていきたいな思います（楽して書きたい）