Reduxの全体像をざっくり理解する

![cc44a8739dd85da75bdedc971d9dba02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335670/d3f4ea36-6c93-c966-bc55-bde8ec3a079a.jpeg)

## 💡全体像をざっくりを理解する

### 登場人物

**Store**
あらゆる状態を管理している倉庫のような奴

**Reducer**
`Store`にある状態を更新する奴
`Store`にある状態を更新できるのは`Reducer`だけ
倉庫（`Store`）の中にいる仕分け人のようなイメージ
`Reducer`が状態を更新するときは、現在の`state`と`action`を受け取る
`action`に応じて新しい状態を返す

**dispatch**
`Reducer`に現在の`state`と`action`を届けるだけな奴
「こういう注文（`action`）来てます〜。現在の`state`（状態）もお届けしました〜。 `Reducer`さん、後はよろしくです〜。」なイメージ

**action**
`dispatch`される注文伝票みたいな奴
`action`（注文伝票）を`Reducer`に届けることで、`Reducer`は`action`に応じて新しい状態を返す

例えばカウントを制御するアプリケーションの場合、
「カウント増やして〜」とか「カウント減らして〜」などの`action`がある

**state**
状態のこと。`Store`で管理されている。

### **全体の流れ**

ここではわかりやすいようにカウントを制御するだけのReactアプリケーションを想定します。

1. ユーザー「カウント+1ボタンポチッと」
2. 現在の`state`（count: 0）と `action`（カウント増やして~）を `Store`に`dispatch`（送る）する
3. `Store`にいる仕分け人`Reducer`が 現在の`state`（count: 0）と`action`（カウント増やして~）を受け取る
4. `Reducer`「えぇーと、現在の`state`（count: 0）と`action`が"カウント増やして〜"ね、OK！ 」
5. `Reducer`「はい完了！ `state`（count: 1）」
6. `React`「お！`state`が更新された。よっしゃー画面を新しい状態に更新するぞー」
7. ユーザー「カウントが"1"になった〜」

## 💡Redux ToolKitで全体像を理解する

### **アプリは単一のコンポーネントと単一のストアを持つ**

Reactアプリケーションが階層の一番上に単一のコンポーネントを持っているように、`Store`も単一です。
1つのアプリケーションで状態を管理する`Store`は1つ。
全ての`state`を1つの`Store`で管理し、必要なデータを適宜取り出せる
`state`をコンポーネントツリーの外部にある`Store`で持つイメージ
アプリの状態は単一の`Store`内のオブジェクトツリーに保存される

```jsx
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import { store } from './app/store'
import { Provider } from 'react-redux'

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

### Slice

`Store`が倉庫だとしたら`Slice`は倉庫の中にある棚のようなイメージ
アプリケーションで扱う状態に応じて`Slice`を切り分けることで、状態の管理がしやすくなる。
例えばcountを扱う`Slice`やtodoを扱う`Slice`などに分けることができる
`createSlice`は `state`,`reducer`,`action`をまとめて作成する関数（便利!!）

```jsx
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'

const initialState = {
  value: 0,
}

// Sliceの作成
export const counterSlice = createSlice({
  name: 'counter', 	// actionの名前の一部になる
  initialState, 	// stateの初期状態
  reducers: { 
    increment: (state) => { // 状態を更新する関数（actionの名前の一部になる）
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
	// 非同期処理を扱うときに使用する
	extrareducer: ...
})

// コンポーネントからactionをdispatchできるようにexport
export const { increment, decrement } = counterSlice.actions

// コンポーネントからstateを参照するための関数をexport
export const selectCount = (state) => state.counter.value

// Storeに登録するためにexport
export default counterSlice.reducer
```

### state

`state`は`initialState` に記述する

```jsx
const initialState = {
  value: 0,
}

export const counterSlice = createSlice({
  //省略
  initialState,
　//省略
})
```

こう書いてもOK

```jsx
export const counterSlice = createSlice({
  //省略
  initialState: {
    value: 0,
	}
　//省略
})
```

### reducer

`reducers`の中に状態を変更する関数をまとめる
`increment`と`decrement`が`reducer`にあたる

```jsx
export const counterSlice = createSlice({
	//省略
  reducers: { 
    increment: (state) => {
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
	//省略
})
```

### action

`action`の名前は`name/reducer`というような形になる（Redux DevToolsでみると分かりやすい）
下記で言うと`counter/increment`のような形になる
ただし、Redux ToolKitが内部でよしなに色々とやってくれるので、`reducers`に登録した`reducer`の名前を下記のように`export`してあげればOK
`export`した`action`をコンポーネントから`dispatch`することで状態が更新される

```jsx
export const counterSlice = createSlice({
  name: 'counter',
  reducers: { 
    increment: (state) => {
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
})

// コンポーネントからactionをdispatchできるようにexport
export const { increment, decrement } = counterSlice.actions
```

### SliceをStoreへ結合

`Store`に登録する`Reducer`の`key`で`state`にアクセスできる
`Reducer`のキーが`counter`なので`state.counter`でアクセスできる

```jsx
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
})
```

### 状態の参照（useSelector）

`useSelector`...`state`に変更があったら自動的に再実行され、コンポーネントを再描画する

```jsx
import { useSelector } from 'react-redux'
import { selectCount } from '../features/counter/counterSlice'

const count = useSelector(selectCount) 

const Counter = () => {
	return(
		<>
			<button>クリック!!</button>
			<span>{count}</span>
		</>
	)
}
```

### 状態の更新（useDispatch）

`useDispatch`は`dispatch`関数を返す
`action`を引数に`dispatch`関数を実行することで`Reducer`が作動し、`state`が更新される
`action`に引数を渡したら`Reducer`で`action.payload`として値を受け取れる

```jsx
import { useDispatch, useSelector } from 'react-redux'
import { selectCount, increment } from '../features/counter/counterSlice'

const dispatch = useDispatch()
const count = useSelector(selectCount) 

const Counter = () => {
	return(
		<>
			<button onClick={()=> dispatch(increment())}>クリック!!</button>
			<span>{count}</span>
		</>
	)
}
```

## 💡全体の流れを簡単におさらい

1. アプリは単一のコンポーネントと単一のストアを持つ
2. `Slice`を作成して`Store`へ結合する
3. `useSelector`を使用して状態の参照ができる
4. `useDispatch`を使用して状態の更新ができる

## Tips

はるか昔、`action`を作るのに色々とごちゃごちゃしていましたが、 `action`の作成に関してあまり意識しなくても良くなりました。
Redux ToolKitが中でいい感じに仕事してくれてると思って頂ければ良いと思います。興味がある方はググって見て下さい。