気持ち
reducer や rx の世界観からすると、JSのオブジェクトへの副作用は悪です。予測可能性を破壊する者ですし、時系列な状態を復元できなくなります。
Reactの一部の操作では、同一参照のオブジェクトのまま値を書き換えると、更新系が壊れるものすらあります。shallow equal だと参照が一致するからですね。
なので基本的にイミュータブルなデータの取り回しをしましょう。
どんなコードをやめたいか
const o = { a: 1 }
o.a = 1
この「メンバーへの代入」が基本的にやめた方がいい操作です。
宣言
基本的に const で宣言します。
明示的に副作用が起こる箇所だけ let で宣言します。
とはいえ、Array と Object は中身を変更できてしまうので、その辺のイディオムが必要です。
Object
before
Object.assign({}, a, b, { c: 1 })
after
{...a, ...b, c: 1}
Object の部分深い部分の書き換え
const obj = { a: { b: { c: 1, d: 2 } }, e: 3 }
const newObj = { ...obj, a: { b: ...obj.a.b, d: 4 } }
が、さすがにだるいので、 immer みたいなヘルパを使うのがおすすめです
const obj = { a: { b: { c: 1, d: 2 } }, e: 3 }
const newObj = immer(obj, draft => {
draft.a.b.d = 4
})
特に配列の immutable 版のAPI を覚え直すのが大変なので、副作用APIスタイルのままイミュータブルオブジェクトを生成できる immer がとてもよいです。
Array
before
a.concat([b]).concat(c)
after
[...a, b, ...c]