動機
reduxで構成されているアプリケーションの中でreducerの部分をもう少しスッキリ書きやすくしたいなーと思ったのがモチベーションでした。
immerの導入
この記事ではイミュータブルの良さについては言及しません。
yarn add immer
ライブラリのバージョンは以下になります。
"typescript": 3.7.5
"redux": 4.0.5
"react-redux": 7.1.3
"immer": 5.3.2
ここでは、簡単なTODOアプリの実装を例に話します。
例えば、ある特定のタスクのタイトルを変更したい場合
従来の書き方
export const changeTaskTitleReducer = (
state: TodoAppState,
{ id, title }: Payload
): TodoAppState => ({
...state,
todoList: {
...state.todoList,
byId: {
...state.todoList.byId,
[id]: {
...state.todoList.byId[id],
title: title
}
}
}
})
immerを使わない場合には、スプレッド演算子を使うことで新しいオブジェクトを返却します。
かなりネストしますし、stateのデータ構造が深い場合はキツイです。
immerを使った書き方
export const changeTaskTitleReducer = (
state: TodoAppState,
{ id, title }: Payload
): TodoAppState =>
produce(state, (draftState: Draft<TodoAppState>) => {
draftState.todoList.byId[id].title = title
})
スプレッド演算子を使った時の書き方に比べるとかなりスッキリしています。
このproduce
関数の中では、第一引数にstate
と第二引数にproducer
と呼ばれる関数を指定します。
producerの中でimmer側がstateをミュータブルに変換してくれます。そしてこの中でデータ変更をします。
immer側で型定義ファイルを用意していくれているので、別途型定義ファイルをインストールする手間もありません。
まとめ
このように部分的に手軽に導入することができました。
一度にすべてimmerに置き換えるのではなく、段階的に置き換えていくこともできるのも良いです。
immerのパフォーマンスについては下記に書いてあります。
https://immerjs.github.io/immer/docs/performance
簡単ではありますが以上です。