最近 Redux Toolkit というReduxのツールがあることを知りました。
公式ドキュメントのチュートリアルを写経してみたところ、かなり良かったのでご紹介します。
Redux Toolkit とは
Redux ToolkitとはReduxをより簡潔に記述するためのツールです。
はじめはredux-starter-kit
という名前で2018年から開発され、2019/10にv1.0がリリースされました。
Redux Toolkitは公式に作られたツールでReduxの公式サイトでも紹介するページがあります。
サンプルコード
Redux Toolkitを使ったコードを見てみましょう。
const todosSlice = createSlice({
name: 'todos', // ①
initialState: [], // ②
reducers: {
addTodo(state, action) { // ③
const { id, text } = action.payload
state.push({ id, text, completed: false }) // ④
}
}
})
// ①:Sliceの名前。Action Typeのプレフィックスに使われる
// ②:Stateの初期値。Todoの配列を持つ。
// ③:Reducerの定義。Action Typeが`todos/addTodo`のAction Creatorが自動的に生成される
// ④:stateの配列にTodoのデータを追加する。
上記のコードはチュートリアルから抜粋したもので、Todoリストのデータを持つSlice1です。
Redux ToolkitではReducerを定義するとAction Creatorを自動的に生成してくれます。
Action Typeを自分で管理する必要もありません。
上記の例ではreducers
に対応するObjectにaddTodo
メソッド(③)があります。
この場合、addTodo()
というAction Creatorが生成されます。
dispath(addTodo(payload))
のように呼び出すと、addTodo
メソッド(③)の内部の処理が行われます。
ちなみにReducerとAction Creatorをそれぞれ定義して書くこともできます。
...
reducers: {
addTodo: {
reducer(state, action) {
const { id, text } = action.payload
state.push({ id, text, completed: false })
},
prepare(text, id) {
return { payload: { text, id } }
}
}
}
Redux Toolkitを使うメリット
コード量が少なくなる
Redux Toolkitを使うとコード量を減らすことができるのが一番のメリットです。
サンプルコードをRedux Toolkitを使わずに書くと下のようになります。
// Action
const ADD_TODO = 'ADD_TODO'
const addTodo = (text, id) => ({
type: ADD_TODO,
id,
text
})
// reducer
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
]
default:
return state
}
}
前節のサンプルコードと比較すると、Actionのコードが必要なので長くなってます。
また、reducerの部分もRedux Toolkitを使ったものと比べて冗長な感じがします。
コードの可読性が高くなる
Redux ToolkitではActionとReducerが同じオブジェクト内で定義されます。
その結果、凝集度が高く可読性コードになっています。
Redux Toolkitを使わない場合、ActionとReducerのコードが違いファイルに定義されたり、同じファイル内でも離れた位置に定義されるのでコードが見づらくなります。
stateのイミュータブル性を意識しなくてよい
Redux Toolkitを使った場合、stateのイミュータブル性を気にすることなくコーディングができます。
前節のサンプルコードのreducersを見ると、pushメソッドを使ってstateに変更を加えています。
...
reducers: {
addTodo(state, action) {
const { id, text } = action.payload
state.push({ id, text, completed: false }) // stateに変更を加えている
}
}
...
Reduxのreducerでは必ずイミュータブルなstateを返す必要がありました。
もし下記の例のようにstateを直接変更して返した場合、正しく再レンダリングされないことがあります。
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
state.push({ id, text, completed: false })
return state // stateを返すと再レンダリングされない
default:
return state
}
}
この仕様はバグの温床になることがありますが、Redux Toolkitを使えば安心です。
TypeScriptの型制御が効く
TypeScriptでReduxを使う場合、typesafe-actions や typescript-fsa などのツールを使っている人が多いかと思います。
Redux Toolkitを使えばそれらのツールを使わなくても型制御を効かせてReduxのコーディングができます。
Redux ToolkitのチュートリアルのコードをTypeScriptで書き直したものをこちらのCode Sandboxに作成したので触ってみてください。
特にsrc/features/todoSlice.ts
を触るとstateにも型制御が効いていることがわかると思います。
最後に
Redux ToolkitはReduxを簡潔に書くことを可能にして、なおかつTypeScript対応など安全にReduxを扱うことができるようになります。
Reduxの公式サイトでもwe strongly recommend that you use it.
と書いてありますし、いまReduxを導入するならRedux Toolkitを入れない理由はないと思います。
ぜひお試しを!
参考
本記事で参考にしたTodoListのソースコード
- Reduxの例:https://codesandbox.io/s/github/reduxjs/redux/tree/master/examples/todos
- Redux Toolkitの例:https://codesandbox.io/s/rtk-convert-todos-example-uqqy3?from-embed=&file=/src/features/todos/todosSlice.js
- TypeScript + Redux Toolkit の例:https://codesandbox.io/s/rtk-ts-convert-todos-example-d0nk7
-
Redux Toolkitでは
Slice
という表現が出てくるのですが、Reducer/Action/Stateをひとかたまりにした概念と自分は理解しています。 ↩