Photo by Lautaro Andreani on Unsplash
こんにちわ!入社して一か月の新米コーダー、サナダです。今回は現在私が勉強しているReactでfluxなアーキテクチャを実現してくれるライブラリReduxについて気になったこと、調べたことを書きたいと思います。
“Do Not Mutate State”
Reduxの公式ガイドラインを見るとRedux利用時のルールがいくつも述べられています。その中でも重要度Aランクに分類されるのが”Do Not Mutate State”(訳:stateを直接変更しないでください)です。
Reduxを利用する上で基本中の基本となるルールとのことですが、サイトの説明を見ても「再レンダリングが正常に機能しない」程度で詳しいことは書いていません。直接stateを編集することは本当に危険なのでしょうか?
変更の種類
本題に入る前に値の変更には2種類のアプローチがあることを理解しなくてはいけません。下記のコードではuserオブジェクトに対して異なる方法で値を変更しています。
// userオブジェクト
const user= {
name: 'tanaka',
age: 20,
gender:'male'
};
// アプローチ1
user.name = 'suzuki';
// アプローチ2
const newUser = { ...user }; // userの内容から新しいインスタンスを生成
newUser.name = 'suzuki';
アプローチ1では値を直接上書きしているのに対し、アプローチ2では一度新しいオブジェクトインスタンスを生成してから値を変更しています。前者をmutable、後者をimmutableな変更と呼びます。つまり”Do Not Mutate State”ルールは裏を返せば、stateの変更にはimmutableな変更を使ってくださいということです。
mutableな変更は無視される
さてimmutableな変更をReduxが好むことは分かりましたが、結局その必要性はどこにあるのでしょうか。それを知るためにreducerを覗いてみましょう。
const reducer = (state = init, action) => {
switch (action.type) {
case 'ADD':
return {
...state,
count: state.count + action.payload // immutableに変更を加えたうえでreturn
};
// その他のアクションに関する処理...
default:
return state
}
}
reducerによって返された新しいstateはそのまま利用されるのでなく、Reduxによって古いstateと厳密等価演算子(===)を用いて高速に比較されます。この演算子をオブジェクトの比較に利用するとプロパティの値ではなくメモリ上の位置が同じかどうかで一致判断が下されるためmutableに変更されたstateは「何も変わっていない」と判断され、最終的にコンポーネントのレンダリングが起きません。これが”Do Not Mutate State”の理由です。
他にもTime Travelデバッキングが効かないなどの理由もあるので気になる方は調べてみてください。
おまけ
Redux中心に話を進めましたがReactでもimmutabilityの考えは重要です。みんな大好きHooksのuseStateもstateをmutableに変更すると正しく検知されません。これは内部的にObject.is()でstateの変更を検知しているためです。
参考サイト
Redux公式サイト(英語)
Immutability in React and Redux: The Complete Guide
WHAT WOULD HAPPEN IF YOU MUTATED YOUR REACT REDUX STATE?