イミュータブルなヘルパー

Rectはミュータブル(mutation - 変更可能)を含め、どのようなスタイルのデータ管理でも使用することが出来ます。 ただし、アプリケーションのパフォーマンスが非常に重要になる部分で、イミュータブル(immutable)なデータを使用出来るのであれば、 アプリケーションの速度を大幅に向上するためのshouldComponentUpdate()メソッドを簡単に実装することが出来ます。

JavaScriptでのイミュータブルなデータの取り扱いは、Clojureのように、 このために設計された言語と比較して難しくなります。 そのため我々は、基本的なデータ表現方法を変更すること無く、 この形式のデータの取り扱いを簡単にするためのシンプルなイミュータブルなヘルパーupdate()を用意しました。 Immutable-jsのより詳しい情報については、、FacebookのImmutable-jsと、 パフォーママンスの向上のセクションでも確認することが出来ます。

主要な考え方

あなたがデータを次のように変更するとします。

myData.x.y.z = 7;
// または...
myData.a.b.push(9);

この場合、前のコピーが上書きされるため、データが変更されたのかどうかを知るすべがありません。 このようにするのでは無く、myDataの新しいコピーを作成して、変更が必要な部分だけを変更する必要があります。 そうすることで、===を使用してshouldComponentUpdate()内でmyDataの古いコピーと新しいコピーの比較をすることが出来ます。

var newData = deepCopy(myData);
newData.x.y.z = 7;
newData.a.b.push(9);

残念ながらディープ・コピーは負荷が高く、不可能なケースも存在しますが、 変更が必要なオブジェクトだけをコピーする事で、そして変更されていないオブジェクトを再利用することで、これを緩和することが出来ます。 それでも残念ながら現在のJavaScriptでは、これは非常に複雑でややこしいものになりかねません。

var newData = extend(myData, {
  x: extend(myData.x, {
    y: extend(myData.x.y, {z: 7}),
  }),
  a: extend(myData.a, {b: myData.a.b.concat(9)})
});

これは、パフォーマンスはある程度向上します(log nオブジェクトだけの浅い(shallow)コピーを行い、残りを再利用)が、 書くのが非常に辛くなります。 この処理全体を繰り返し見返して下さい。 これでは複雑なだけで無く、バグの温床になりかねません。

訳注: log nはおそらく二分探索のように、処理が進むほど負荷が軽減される様を表していると思われますが確証はありません。

update()は、こういったパターンのコードを簡単に書けるようにしてくれるシンプルなシンタックスシュガーを提供します。 先ほどのコードは次のようになります。

var newData = React.addons.update(myData, {
  x: {y: {z: {$set: 7}}},
  a: {b: {$push: [9]}}
});

冗長性の無いこの文法には少し慣れが必要(MongoDBのクエリー言語からインスパイア)ですが、 静的な分析が可能であり、ミュータブルなものと比べるとタイピングが少なく済みます。

$の接頭辞を持つキーはコマンドと呼ばれます。 変更可("mutating")のデータ構成は、ターゲット(target)と呼ばれます。

利用可能なコマンド

{$push: array}
ターゲット上でarrayの全ての項目をpush()します。
{$unshift: array}
ターゲット上でarrayの全ての項目をunshift()します。
{$splice: array of arrays}
arraysの各項目が、ターゲット上でsplice()を、各項目によって提供される引数付きで呼び出します。
{$set: any}
ターゲット全体を置き換えます。
{$merge: object}
対象とobjectをキーでマージします。
{$apply: function}
現在の値を関数に渡し、その新しい戻り値で更新します。

コマンドの使用例

push

var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]

initialArrayは、[1, 2, 3]のままになります。

入れ子のコレクション

var collection = [1, 2, {a: [12, 17, 15]}];
var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
// => [1, 2, {a: [12, 13, 14, 15]}]

これはコレクションのインデックスの2番目であるaのキーにアクセスし、 spliceをインデックスの1番目から1つの項目に対して行い(17を削除)、13と14を挿入します。

現在の値を基にしてその値を更新

var obj = {a: 5, b: 3};
var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
// => {a: 5, b: 6}
// 同じ処理になりますが、より深いネストのコレクションでは冗長になります。
var newObj2 = update(obj, {b: {$set: obj.b * 2}});

(浅い (Shallow))マージ

var obj = {a: 5, b: 3};
var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}

 Back to top

© 2013-2017 Facebook Inc.
Documentation licensed under CC BY 4.0.

このページは、ページトップのリンク先のReact内のページを翻訳した内容を基に構成されています。 下記の項目を確認し、必要に応じて公式のドキュメントをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。

  • ドキュメントの情報が古い可能性があります。
  • "訳注:"などの断わりを入れた上で、日本人向けの情報やより分かり易くするための追記を行っている事があります。