React + Reduxを基本からまとめてみた【1】【Redux Toolkit】

## Reduxとは

- 状態管理のこと
- reactのみでアプリケーションを作成するより手軽にStateを管理できる
- アプリケーションの規模が大きくなればなるほど有り難みが出てくる
- 複雑なアプリケーションを作成できるサポートアイテム

Reduxは状態管理ライブラリ(State Management Library)と呼ばれている。
状態管理という言葉ではどのような機能を持っているのかイメージすることが難しいので、最初は『すべてのコンポーネントで1箇所に保存されているデータを共有できる仕組み』と考えた方がわかりやすい。



##なぜReduxを使うのか

『React』では、『Redux』を利用することで全てのコンポーネントからアクセス可能なデータを一箇所で一元管理することができるから。

Reactでは複数のコンポーネントを構成してアプリケーションを構築するため、コンポーネント間でデータの受け渡しが必ず必要になり、コンポーネント間でデータを渡す場合は、親コンポーネントから子コンポーネントへpropsを使って行う。
しかし、propsでは親子関係のないコンポーネント間ではデータを渡すことができない。また、親と子のみの関係であればpropsを一度渡すだけで良いが、子コンポーネントに孫コンポーネントがあるとpropsをバケツリレーのように渡さないといけない。

#####『Redux』を利用すれば、どのコンポーネントからもアクセス可能なデータを一元管理する場所があれば、バケツリレーの問題を解消することができる。

『Redux』を利用すればどのコンポーネントからも同じ方法で共有したデータにアクセスすることが可能になり、『props』では親から渡されたデータを子コンポーネントで更新することはできないが『Redux』であればどのコンポーネントからも共有したデータ更新することが可能になる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939638/52b83576-fb4b-25ec-ec94-3608f4d6223e.png)

##Redux Toolkitとは

Reduxは複数のコンポーネントからアクセス可能なデータを一箇所で一元管理するためのライブラリで、Reduxのみでは以下のような問題点がある。

- Redux Storeを構成することが複雑すぎる
- 大規模のアプリケーションを構築するにはたくさんの追加パッケージをインストールする必要がある
- Reduxを利用するためには定型文的なコードを大量に記述する必要がある

上記の問題点を解消することを目的に開発されたパッケージが『Redux Toolkit』。Reduxの公式ホームページではReduxを利用する際に『Redux Toolkit』を利用することを推奨している。

『Redux Toolkit』を利用することで定型分的なコード量を減らすことができる上、開発者が陥りがちな問題を避けるためにこれまで蓄積されたベストプラクティスが反映されているためReduxのコードを効率よく記述できる。


##環境構築
①プロジェクトを作成する。

```
 $ npx create-react-app <プロジェクト名>
```
② logo.svg, App.test.js, reportWetVitals.js, setupTests.jsを削除する。

##Reduxを利用しないカウンターの作成

① App.jsファイルを編集する。

プロジェクトフォルダ作成後App.jsを開いてRedexを利用しない場合のカウンターのコードを記述する。

※ useState Hookでcount変数を定義し、ボタンを2つ用意します。片方のボタンをクリックするとcountの値が1増え、もう一方のボタンをクリックするとcountの値が減る。

```App.js
import './App.css';
import { useState } from 'react';

function App() {
  const [count, setCount] = useState(0);
  return (
    <div className="App">
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>Up</button>
      <button onClick={() => setCount(count - 1)}>Down</button>
    </div>
  );
}

export default App;
```

##Reduxライブラリのインストール

① Reduxとredux toolkitパッケージのインストールを行う。

```
$ npm install @reduxjs/toolkit react-redux
```

##Redux Toolkitの設定

###Storeの作成

Reduxでは全てのコンポーネントからアクセス可能なstoreと呼ばれる場所を作成する必要がある。srcフォルダにreduxフォルダを作成しその中にstore.jsファイルを作成する。

①プロジェクトディレクトリにstoreディレクトリを作成しindex.jsファイルを作成して、index.jsファイルの中でcreateStore関数を使ってstoreの作成を行う。

```redux/store.js
import { configureStore } from '@reduxjs/toolkit';

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

###Providerコンポーネントの設定

store.jsファイル作成後、作成したstoreに全てのコンポーネントからアクセスできるようにindex.jsファイルを開いてAppコンポーネントをProviderで包む。
Providerはreact-reduxからimportし、作成したstoreをimportしてstoreをpropsとしてProviderコンポーネントに渡す。


```index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { store } from './redux/store';
import { Provider } from 'react-redux';

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

###Sliceファイルの作成

カウンターの変数count、countの初期値やcountの値を更新する関数をRedux ToolkitではSliceファイルに作成する。Sliceファイルは管理したいデータを目的別/機能別に分けることができるのでここではカウンターの変数countに関する設定をcounterSlice.jsファイルにすべて設定する。
もし、ユーザ情報をRedux Toolkitで管理したい場合は、userSlice.jsといった名前の別ファイルを作成しユーザ情報の初期値や更新に利用する関数を記述する。Sliceでデータを目的別にわけることでデータ管理を混乱をさけ、効率的に管理することができる。
Sliceファイルの中で初期値、reducer、Action Creatorを設定することができるためそれぞれの処理を複数のファイルに分けて記述する必要がない。

① reduxフォルダの中にcounterSlice.jsファイルを作成し、Redux ToolkitからcrateSliceをimportする。creteSliceの引数にはname, initialState, reducersプロパティを持つオブジェクトを指定する。

nameにはSliceを識別するための名前を設定し、initialStateには共有するデータ(state)の初期値を設定し、reducersの中にはstateを更新するための関数を設定する。

下記のコードではsliceの名前をcounter、countの初期値を0に設定し、reducersの中で関数increaseとdecreaseのreducerを定義している。increaseでは関数の引数にstateが入りcountの値を1増やす処理を行う。decreaseでは現在のcountの値を1減らす処理を行う。

```Redux/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0,
  },
  reducers: {
    increase: (state) => {
      state.count += 1;
    },
    decrease: (state) => {
      state.count -= 1;
    },
  },
});
```

② reducersの中で設定した関数increase, decreaseはredux Toolkitでは自動で同名のAction Creatorを作成する。Action Creatorを後ほど出てくるdispatchで指定するためAction Creatorをexportして他のコンポーネントからimportできるようにする。

```Redux/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0,
  },
  reducers: {
    increase: (state) => {
      state.count += 1;
    },
    decrease: (state) => {
      state.count -= 1;
    },
  },
});

export const { increase, decrease } = counterSlice.actions;

export default counterSlice.reducer;
```

###StoreへのSliceの追加

① 作成したcounterSliceをstore.jsでimportしてreducerに設定する。

```Redux/store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

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

```

複数のSliceを作成した場合は作成したSliceをimportしてreducerプロパティのオブジェクトに追加することで各Sliceで設定したstateをすべてのコンポーネントからアクセスすることが可能になる。combineReducersを利用しなくてもRedux Toolkitが自動で設定を行う。

#####これでRedux Toolkitの設定は完了。

###useSelectorの設定

useSelector Hookを利用することでcounterSliceで設定したcountの値を取得することができる。stateのドットの直後に設定しているcounterはstore.jsのreducerに設定したオブジェクトのプロパティのcounterを対応する。counterSlice.jsファイルのnameで設定した”counter”ではない。state.countでもないことも注意してください。

```App.js
import './App.css';
import { useSelector } from 'react-redux';

function App() {
  const count = useSelector((state) => state.counter.count);
  return (
    <div className="App">
      <h1>Count: {count}</h1>
    </div>
  );
}

export default App;
```
counterSliceに設定したcountを表示させるだけであればuseSelectorを
利用するだけで完了。useSelectorでcountの値を取得。

###useDispatchの設定

countの値を更新するためにはAppコンポーネントでAction Creatorsを呼び出す必要があり、Action Creatorsを実行するためにはdispatchが必要となるためuseDispatchをimportする。Action CreatetorsはcounterSlice.jsファイルでexportしているのでそのexportをAppコンポーネントでimportする。

```App.js
import './App.css';
import { useSelector, useDispatch } from 'react-redux';
import { decrease, increase } from './redux/counterSlice';

function App() {
  const count = useSelector((state) => state.counter.count);
  const dispatch = useDispatch();
  return (
    <div className="App">
      <h1>Count: {count}</h1>
      <button onClick={() => dispatch(increase())}>Up</button>
      <button onClick={() => dispatch(decrease())}>Down</button>
    </div>
  );
}

export default App;
```

###カウンター画面

Reduxを利用しないコードからRedux Toolkitへ書き換え作業は完了。
Reduxを利用しないコートでは他のコンポーネントでcountにアクセスするためにはpropsを利用することができますがReduxを利用している場合はindex.jsのProviderで包んでいるコンポーネント以下にあるコンポーネントからであればどこからでもアクセスすることができる。その時にはuseSelector Hookでアクセスを行い、useDispatch Hookを利用して更新を行う。

##Redux DevToolsでの確認

Chromeブラウザを利用している場合はExtentionsのRedux DevToolsをインストールしていればRedux Toolkitを利用して設定したデータの状態を確認することができる。
ブラウザのデベロッパーツールを開いてReduxタブを選択することで下記の画面が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939638/ece6fe0a-b39e-032e-dfc8-0d7f473afb65.png)



## 参考サイト

[【Redux入門】初学者でも理解できるReduxの仕組みを解説します！(Redux Toolkitを使用)](https://www.youtube.com/watch?v=KuRu5wOyY_c)