React Reduxには今後Redux Toolkitも使うのがいいと思う

ReactをTypeScriptで始めることが随分楽になったと感じています。Create React Appの以下のコマンドでOKです。

```zsh
$ npx create-react-app my-app --template typescript
```
https://create-react-app.dev/docs/adding-typescript/#installation

2020年2月の中頃からReduxのテンプレートが利用可能となり、以下のコマンドで始めることができます。

```zsh
$ npx create-react-app my-app --template redux
# or 
$ npx create-react-app my-app --template redux-typescript
```

https://github.com/reduxjs/cra-template-redux

このReduxテンプレートにはRedux Toolkitが使われています。https://redux-toolkit.js.org/
本格的に利用していくのはこれからですが、使わない場合と比べてここが便利だ（そうだ）というあたりを紹介します。

# 利点
## 初期設定が簡単
次のmiddlewareが設定済みとなります。

- Redux Thunk
- immutable-state-invariant
- serializable-state-invariant-middleware

Redux Thunkは非同期通信のためのライブラリで、他2つは開発用のmiddlewareでReduxで禁止しているstateの変更を検知してくれます。

また、Redux Devtools Extensionも有効になっています。
これらを自分で適用しようとすると少々面倒です。

## createSliceでActionのコードは不要に
公式ドキュメントからの抜粋となります

```js
const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment: state => state + 1,
    decrement: state => state - 1
  }
})

const store = configureStore({
  reducer: counterSlice.reducer
})

const { actions, reducer } = counterSlice
const { increment, decrement } = actions

```
こんな感じでAction, Reducerを定義できます。これによりほぼActionのコードがなくなるのではと期待しています。今まではComponent, Action, Reducerに対してロジックが多少入ることが気になっていましたが、Component, Reducerでそれぞれの責務でロジックを実装できそうです :smiley:

Reducerのネストはいつも通りな感じです。

```js
const sliceA = createSlice({
  name: "reducerA",
  //...
})
const sliceB = createSlice({
  name: "reducerB",
  //...
})

import { combineReducers } from "@reduxjs/toolkit"
const mergeReducer = combineReducers({
  reducerA: sliceA.reducer,
  reducerB: sliceB.reducer,
})

```


## 非同期通信にはRedux Thunkが採用


```js

const createUser = createAsyncThunk(
  'users/createUser',
  async () => {
    // API処理
  }
)
```

createAsyncThunkでは次の3つのActionを生成してくれます。

- pending
- fulfilled
- rejected

sliceではextraReducersのbuilderを利用して追加します。createAsyncThunkで定義されたActionを利用するためです。

```reducer.js
const userSlice = createSlice({
  name: "user",
  initialState: {
    user: null,
  },
  reducers: {},
  extraReducers: builder => {
    builder.addCase(createUser.pending, (state, action) => {})
    builder.addCase(createUser.fulfilled, (state, action) => {})
    builder.addCase(createUser.rejected, (state, action) => {})
  }
})

```

```component.jsx
import { useDispatch } from "react-redux"

function UserComponent() {
  const dispatch = useDispatch()

  const handleSubmit = async () => {
    const resultAction = await dispatch(createUser())
    // createAsyncThunkで生成されるActionと比較して処理を変更できる
    if (createUser.fulfilled.match(resultAction)) {
      // success
    } else {
      // error
    }
  };
  return (
    <div>
      <form></form>
      <button onClick={handleSubmit}>submit</button>
    </div>
  )
}

```


# やっておいた方がいいこと
## RootReducerの型定義
TypeScriptで利用する際に用意しておいた方がいいです。以下で定義しておきます。

```store.ts
import { combineReducers, configureStore } from "@reduxjs/toolkit"

export const rootReducer = combineReducers({
  moduleA: moduleAReducer,
})
export type RootReducerType = ReturnType<typeof RootReducer>

```
RootとなるReducerの型定義はあると便利ぐらいの気持ちです。

## useDispatchのラップ

```store.ts
import { configureStore } from "@reduxjs/toolkit"
const store = configureStore({
  reducer: rootReducer
})
export type AppDispatch = typeof store.dispatch
```

```customHooks.ts
import { useDispatch } from "react-redux"
function useAppDispatch(): AppDispatch {
  return useDispatch<AppDispatch>()
}
```

createAsyncThunkで型定義のエラーを起こさないためです。


# 注意点
## ImmerによるReducerのstateのImmutable

以下のようにstateを直接変更するようなコードを書いても問題ありません。Redux ToolkitではImmerを利用しており、実際にstateを変更しているわけではないとのことです。

```ts
interface CounterState {
  value: number;
}

const initialState: CounterState = {
  value: 0,
};

export const slice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: state => {
      state.value += 1;
    }
  },
});

```

# まとめ
煩雑な設定がなくなり、ActionやReducerの実装も統一できそうです。これからReduxを始める人、そうでない人にもおすすめです :smiley: 

# 参考

- https://create-react-app.dev/docs/adding-typescript/#installation
- https://github.com/reduxjs/cra-template-redux
- https://redux-toolkit.js.org/