Alec Larson氏は数日前、JavaScriptライブラリImmerの4回目となるメジャーイテレーションをリリースした。今回のリリースでは、重要なエッジケースに対する修正が行われている。Immerは、コピーオンライト機構を実装することによって、不変な状態を変更可能であるように操作可能にするJavaScriptパッケージである。Immerは先頃、今年の"Breakthrough of the year React open source award"と、"Most impactful contribution JavaScript open source award"という2つの賞を受賞している。
Immer("常に"という意味のドイツ語)は、可変な状態(mutable state)を操作する単純さと利便性を維持しながら、不変な状態(immutable state)を使用できるようにするパッケージである。その目的を実現するため、Immerでは、JavaScriptプロキシに関連して使用されるコピーオンライトメカニズムである構造共有(structural sharting)を利用している。
具体的には、開発者が変更するのは、currentStateの一時的なプロキシであるdraftStateである。その変更内容に基づいた結果がnextStateを生成し、変更されていない部分をcurrentStateと共有する。この方法によって、不変データのメリットをすべて維持しながら、通常と同じようにデータを変更することができるのだ。
次の例では、
import produce from "immer"
const baseState = [
{
todo: "Learn typescript",
done: true
},
{
todo: "Try immer",
done: false
}
]
const nextState = produce(baseState, draftState => {
draftState.push({todo: "Tweet about it"})
draftState[1].done = true
})
draftState
は変更されるが、baseState
は変更されない。またnextState
は、draftState
への変更をすべて反映した(変化していない部分を構造的に共有した)、新たな不変木である。
Immer v4では、繰り返しによって多くの問題を発生させるエッジケースが修正されている。
修正前のImmerは、変更点以外に不変性を付与することはしていなかった。このため、produce
APIを使用した結果生じるnextStateオブジェクトは、変更されていなければいつでも変更可能になっていた。次のコードサンプルは、その誤った動作を示すものだ。
const d: D = {a: {b: 2}, z: {y: 3}};
const immutable = produce(d, draft => {
draft.a.b = 1;
});
// Cannot modify a.b
expect(() => immutable.a.b = 5).to.throw("");
// But can modify z.y!!
immutable.z.y = 4;
expect(immutable.z.y).eql(4);
Immer v4では、深く凍結されたオブジェクトツリーを返すことで、従来の挙動を修正して、immutable.zy
が変更できないようにしている。
不変のデータ構造は、簡便なパフォーマンス最適化、Undo/Redo機能、更新のトレーサビリティ向上などを可能に手段として、JavaScript開発者に広く利用されている。アプリケーションの状態が"凍結された(frozen)オブジェクトのスナップショット"として表現され、reducerと呼ばれる純粋関数のカテゴリによってのみ変更可能なReact/Reduxコンテキストでは、これが重要だ。実際にRedux-ecosystem-linksのページには、Reduxで不変のデータ構造を扱うパッケージが70ほどリストアップされている。
Immerは標準JavaScriptとの相互運用性やパフォーマンス、そのほかの機能において、同様なプロダクトを凌駕する。ReactにおけるImmerの台頭については、Reactチームのメンバであり、ReduxとCreate React Appの作者のひとりでもあるDan Abramov氏が説明している。
成功のためのレシピ — デバッグがしやすく、記述が面倒でないこと。Immerを作ってくれた@mweststrateに感謝! ―
ただし、ImmerはES6プロキシをベースとしており、旧式のブラウザではポリフィル(polyfill)の使用が必要になるため、パフォーマンスに影響する可能性がある。さらに、ドキュメントにも記載されているが、プロキシを使用することによって発生する落とし穴にも注意が必要だ。
Immerは2019年に、2つの賞を受賞した。"Most impactful contribution JavaScript open source award"と、"Breakthrough of the year React open awardは、JavaScriptエコシステムに貢献し、"さらなる開発への新たな次元と可能性、新たなコンセプトとアイデアを最初に実現すると同時に、その将来に対する大きな期待"を備えたプロジェクトを選ぶものだ。
Immerを開発したMichel Weststrate氏は、状態管理ライブラリmobxの開発者でもある。
Immerは、MITライセンス下で利用可能なオープンソースソフトウェアである。Immer GitHubプロジェクトとオープンコレクティブを通じて、コントリビューションとフィードバックを募集中だ。