目次
- Reactで変数がイミュータブルであることがなぜ重要か
- eslint-plugin-functionalを使ってイミュータブルを強制する
Reactで変数がイミュータブルであることがなぜ重要か
※ そんなのもう知ってるよ!って方はスキップしてください。
そもそもイミュータブルとは?
はこちらの記事が分かりやすいので参考にしていただければ
Reactにおけるイミュータブルの重要性
一般にイミュータブルだと一度定義した変数が不変なため、コードの挙動が予測可能というメリットがある。
さらに、Reactにおけるイミュータブルであることのメリットは状態(変数)を更新したにもかかわらず、Reactがそれを検知できず、画面に更新が反映されないというバグ?を防ぐことができることできること。
ミュータブルな変更をおこなった場合にどうなるか
Reactのコンポーネントはstateまたはpropsが更新されたら、更新を検知し再レンダーするが、"更新された"の判断はimmutableな変更を前提にしている。つまり、メモリの参照先を比較している。なので、オブジェクト型のstateやpropsをmutableに変更した場合、メモリの参照先は変更前後で同じなため、reactは変更を検知できない。
stateやpropsをミュータブルに変更した場合、再レンダーされないだけで、値としては更新されているので、別のトリガーで再レンダーが起こったときに、隠れていたの差分が現れて、バグっぽく動いてしまう。
↓mutable changeを押した差分が、immutable changeをした際に現れる。
https://codesandbox.io/s/react-typescript-forked-fd5r40?file=/src/App.tsx
上の例ではコンポーネントの自身のstateの更新の例を挙げたが、constで定義されるような通常の変数も、コンポーネント内で使用している他のコンポーネントのpropsに渡した場合に同じことが起こるため、変数もimmutableであるべき。
上記のような理由から、特にReactでは変数全般はイミュータブルであることが重要。
イミュータブルにするにはどうしたらいいか?
Typescriptでオブジェクト型の変数をイミュータブルにするにはreadonlyをつければOK。参考
ただ、、、
開発中に毎回readonlyをつけるのは面倒だし、つけ忘れがあるかもしれない、、、
そこで、eslintにeslint-plugin-functionalというimmutableを強制してくれる設定があるので使おう、というお話!
eslint-plugin-functionalを使ってイミュータブルを強制する
設定方法
基本的に公式のgithubを見ながらeslintを設定すれば良い。
eslint-plugin-functionalは
An ESLint plugin to disable mutation and promote functional programming in JavaScript and TypeScript.
とあるように、名前の通りjs, tsの関数型プログラミングをサポートするもので、イミュータブルを強制する以外にも、さまざまな設定ができる。
設定と適用されるルールの対応は、表になっている。
例えば、 no mutationsのルールの場合
設定は以下の3種類があり、
🙈: plugin:functional/no-mutations
🙉: plugin:functional/lite
🙊: plugin:functional/recommended
それぞれの設定の際に適用されるルールは✅が表で付いている項目になる。
※↓の通り、no mutationsの場合はどの設定にしても全てのルールが適用される。
ミュータブルな変更をさせないだけであれば以下の設定でOK。
{
...
"plugins": [
...
"functional"
],
"extends": [
...
"plugin:functional/no-mutations",
]
}
プラスアルファでより関数型の要素を取り入れたいのならliteやrecommendedを設定すると良い。
個人的にはliteにして、no-return-voidなど、どうしてもないと不便なもののみ個別にoffにするのが良さげ。
その他設定しておいた方がいいこと
-
vscodeのeslint拡張機能をいれ、保存時のeslint自動修正
readonlyを自分で毎回書かなくて良い。 -
自動テストでのeslintもチェック
仕組みとしてイミュータブルであることを保証できる。レビューアとしてもイミュータブルになっていることが保証されているので、レビュー観点の削減にもなる。