|
|
|
---
|
|
|
|
id: update
|
|
|
|
title: 不変性のヘルパ
|
|
|
|
permalink: update-ja-JP.html
|
|
|
|
prev: create-fragment-ja-JP.html
|
|
|
|
next: pure-render-mixin-ja-JP.html
|
|
|
|
---
|
|
|
|
|
|
|
|
Reactは変化を含む、使用したいデータマネジメントのスタイルであればどういったものであっても使用することができます。しかし、アプリケーションの、パフォーマンスが重要な部分において不変なデータを使用できる場合は、速い `shouldComponentUpdate()` メソッドを実行して、簡単にアプリケーションのスピードを著しく速くすることができます。
|
|
|
|
|
|
|
|
[Clojure](http://clojure.org/)のような、不変なデータの扱いのためにデザインされた言語よりも、JavaScriptでそれを行うことは難しいです。しかし、単純な不変性のヘルパである、 `update()` が提供されています。それは、データがどのように表されるかということを基本的には変更すること *なく* データのタイプを扱うことを簡単にします。Immutable-jsについての詳細は、Facebookの[Immutable-js](https://facebook.github.io/immutable-js/docs/#/)や[進歩したパフォーマンス](/react/docs/advanced-performance.html)をご覧ください。
|
|
|
|
|
|
|
|
## 主要な考え
|
|
|
|
|
|
|
|
もし変更する予定のデータが以下のようなものであれば、
|
|
|
|
|
|
|
|
```js
|
|
|
|
myData.x.y.z = 7;
|
|
|
|
// または...
|
|
|
|
myData.a.b.push(9);
|
|
|
|
```
|
|
|
|
|
|
|
|
以前のコピーが上書きされるので、どのデータが変更されたか判断する方法はありません。代わりに、 `myData` の新しいコピーを作成する必要があり、変更される必要がある部分のみを変更します。それから、 `myData` の古いコピーと新しいコピーを `shouldComponentUpdate()` の中で以下のように、3つのイコールを使用して比較することができます。
|
|
|
|
|
|
|
|
```js
|
|
|
|
var newData = deepCopy(myData);
|
|
|
|
newData.x.y.z = 7;
|
|
|
|
newData.a.b.push(9);
|
|
|
|
```
|
|
|
|
|
|
|
|
不幸なことに、ディープコピーはコストがかかり、不可能なときもあります。変更される必要があるオブジェクトをコピーすることと、変更されていないオブジェクトを再利用することによってのみ、これを代替することができます。不幸なことに、今日のJavaScriptでは、こういったことは面倒です。
|
|
|
|
|
|
|
|
```js
|
|
|
|
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` オブジェクトのシャローコピーを作成し、残りを再利用するため)、記述するのには多くのコストがかかります。全てのコードの繰り返しを見てください。それらはつまらないものではなく、多くのバグの表面を提供します。
|
|
|
|
|
|
|
|
`update()` はこのようなパターンにおいて、コードを簡単に記述するための単純な糖衣構文を提供します。そのコードは以下のようになります。
|
|
|
|
|
|
|
|
```js
|
|
|
|
var newData = React.addons.update(myData, {
|
|
|
|
x: {y: {z: {$set: 7}}},
|
|
|
|
a: {b: {$push: [9]}}
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
シンタックスは少し慣れが必要ですが([MongoDBのクエリ言語](http://docs.mongodb.org/manual/core/crud-introduction/#query)にインスパイアされているため)、冗長性はありません。静的に分析し、変更ができるバージョンと比べてタイプする量がすごく増えているわけではありません。
|
|
|
|
|
|
|
|
`$` から始まるキーは *コマンド* と呼ばれます。それらが「変更する」データ構造は *ターゲット* と呼ばれます。
|
|
|
|
|
|
|
|
## 使用できるコマンド
|
|
|
|
|
|
|
|
* `{$push: array}` ターゲットに `array` の全ての要素を `push()` します。
|
|
|
|
* `{$unshift: array}` ターゲットの `array` の全ての要素を `unshift()` します。
|
|
|
|
* `{$splice: array of arrays}` `arrays` の全ての要素について、その要素によって提供されるパラメータのターゲットにおいて、 `splice()` を呼び出します。
|
|
|
|
* `{$set: any}` ターゲットを完全に置き換えます。
|
|
|
|
* `{$merge: object}` `object` のキーをターゲットとマージします。
|
|
|
|
* `{$apply: function}` 現在の値を関数に渡し、返された新しい値によってそれを更新します。
|
|
|
|
|
|
|
|
## 例
|
|
|
|
|
|
|
|
### 単純なプッシュ
|
|
|
|
|
|
|
|
```js
|
|
|
|
var initialArray = [1, 2, 3];
|
|
|
|
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
|
|
|
|
```
|
|
|
|
`initialArray` は `[1, 2, 3]` のままです。
|
|
|
|
|
|
|
|
### ネストしたコレクション
|
|
|
|
|
|
|
|
```js
|
|
|
|
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]}]
|
|
|
|
```
|
|
|
|
|
|
|
|
これは、 `collection` のインデックスが `2` である要素にアクセスし、インデックスが `1` である要素に( `17` を削除し)`13` と `14` を挿入することで繋ぎ合わせます。
|
|
|
|
|
|
|
|
### 現在の値に基づいて値を更新すること
|
|
|
|
|
|
|
|
```js
|
|
|
|
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}});
|
|
|
|
```
|
|
|
|
|
|
|
|
### (シャロー)マージ
|
|
|
|
|
|
|
|
```js
|
|
|
|
var obj = {a: 5, b: 3};
|
|
|
|
var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
|
|
|
|
```
|