グローバルステートの管理にはReduxを使おう（仕組み〜簡単な実装まで）


# ◆ 目次
**・はじめに（Reduxとは）**

**・Reduxの管理の仕組み**

**・定義方法**

**・実践してみよう**
<br>
<br>

# ◆ はじめに（reduxとは）
Reduxとは、Reactとは別でグローバルステートを管理するライブラリ。
<br>
**【 グローバルステート 】**
アプリケーション全体で管理するステート。ReactでいうuseContext。

**【 ローカルステート 】**
特定のコンテキスト内のみで管理するステート。ReactでいうuseState。
<br>

# ◆ Reduxの管理の仕組み

### ・Store
![スクリーンショット 2023-03-25 15.45.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/2ee59a7a-dd9b-7730-5324-3f947af3aad4.png)

Reduxのデータの保存場所。
状態を保管するステートと、ステートを更新する関数（Reducer）を持っている。
<br>
### ・Disptach
![スクリーンショット 2023-03-25 15.54.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/6b03f72f-c9c2-49f0-476f-cd3e86448061.png)

Reducerを呼び出すために実行する関数。
Dispatchを呼び出すことでReducerが実行され、ステートが更新される。

## ・全体的な流れ
![スクリーンショット 2023-03-25 15.59.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/8392b53e-a7a3-ff32-bd82-2ac09a2803be.png)

**① 初期値のステートがUIに表示される。Dispatchを実行するためのイベントをUIで実行する。**
↓
**② Dispatchを実行したことでReducerが呼び出される。ステートが更新される。**
↓
**③ 更新されたステートが画面に表示される。**
<br>

# ◆ 定義方法
## ・更新関数の定義

```react
import { createSlice } from "@reduxjs/toolkit";

const Example = createSlice({
  // Sliceの名前
  name: 'example',
  // ステートの初期値 ※プロパティ名は任意
  initialState: 0,
  // 更新関数をオブジェクトで定義
  reducers: {
  // 定義したいメソッドを記載
  }
})

// アクションクリエイターの定義
const { /* 定義したメソッド */ } = example.actions;
/*
 * 【アクションクリエイター】
 * Dispatch（更新関数を呼び出す関数）の引数に指定する※Actionを定義する関数のこと
 * createSliceでは、アクションクリエイターが自動で作成される。
 */

export { /* アクションクリエイター名 */ }
export default example.reducer;
```

### ※Actionとは
Actionとは、ユーザーが行なった操作をオブジェクトで表現したものと考えれば良い。
```react
Action : {
  type: "アクションの種類",
  payload: "アクション時に利用するデータ"
}
```
https://www.wakuwakubank.com/posts/703-react-redux/#index_id4

<br>

## ・Storeの定義

```react
import { reducer } from "更新関数を定義したファイルの階層"
import { configureStore } from "@reduxjs/toolkit"

export default configureStore({
  reducer: {
    // 先ほど定義した更新関数をオブジェクト内に定義 ※プロパティ名は任意
    example: reducer
  }
});

```

## ・Dispatchの取得

```react
import { useDispatch } from "react-redux";

const Example = () => {
  const dispatch = useDispatch();
}
```

## ・ステートの取得

```react
import { useSelector } from "react-redux";

const Example = () => {
  const state = useSelector(state => state);
}

/*
 * useSlector
 * 
 * 引数にはコールバック関数を定義する。
 * コールバック関数の引数のstateは、Reduxで現在管理しているState（グローバルステート）を表している。
 * 今回のExampleコンポーネントでは、管理しているStateをそのまま出力している。
 */
```

## ・Storeへのアクセス

```react
import { Provider } from "react-redux";
import store from "configureStoreを用いてStoreを定義したファイルの階層"

const App = () => {
  return (
    <Provider store={store}>
      {/* Storeへのアクセスを可能にしたいコンポーネントをchildrenに設定　*/}
      <Example></Example>
    </Provider>
  )
}
```
<br>


# ◆ 実践してみよう

![スクリーンショット 2023-03-26 15.35.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/c401eb03-0c35-11bb-fe01-20c54aec995a.png)

ボタンを押すとボタンに書かれた数字分、表示された数字が加減されるものを作成します。

## ①更新関数の定義

```react
import { createSlice } from "@reduxjs/toolkit";

const counter = createSlice({
  // Sliceの名前
  name: 'counter',
  // 初期値の値
  initialState: 0,
  // 更新関数の定義
  reducers: {
  // プラスの時のメソッド
    add(state, {type, payload}) {
      return state + payload;
    },
  // マイナスの時のメソッド
    minus(state, {type, payload}) {
      return state - payload;
    }
  }
})

// アクションクリエイターの定義
const { add, minus } = counter.actions

// アクションクリエイターとReducerのexport
export { add, minus }
export default counter.reducer;
```
<br>

## ②Storeの定義

```react
import { reducer } from "reducerを定義したファイルの階層"
import { configureStore } from "@reduxjs/toolkit"

export default configureStore({
  reducer: {
    counter: reducer
  }
});
```
<br>

## ③ボタンコンポーネントの作成

```react
import { add, minus } from "アクションクリエイターを定義したファイルの階層";
import { useDispatch } from "react-redux";

const CounterButton = ({ calcType, step }) => {
  // dispatchの取得
  const dispatch = useDispatch();
  // dispatch呼び出し用のイベントハンドラの定義
  const clickhandler = () => {
  // アクションクリエイター（calctTypeの値に応じて条件分岐）
  // アクションクリエイターによって作成したActionを引数に格納し、dispatchの引数に指定して実行 
    const action = calcType === "+" ? add(step) : minus(step); 
    dispatch(action);
  }

  return (
    <button onClick={clickHandler}>{calcType}{step}</button>
  )
}

export default CounterButton;
```
<br>

## ④表示用のコンポーネントの作成
```react
import { useSelector } from "react-redux";

const CounterResult = () => {
  // ステートの取得
  const state = useSelector(state => state);

  return (
    <p>{state}</p>
  )
}
export default CounterResult;
```
<br>

## ⑤画面表示
・App.js
```react
import { Provider } from "react-redux";
import store  from "storeを定義したファイルの階層";
import CounterButton from "定義したファイルの階層";
import CounterResult from "定義したファイルの階層";

const App = () => {
  return (
    <>
      <Provider store={store}>
        <CounterResult />
        <CounterButton calcType={"+"} step={2}/>
        <CounterButton calcType={"-"} step={2}/>
        <CounterButton calcType={"+"} step={10}/>
        <CounterButton calcType={"-"} step={10}/>
      </Provider>
    </>
  )
}
```
以上で完成です。