Immutable.js
不変の永続データ構造を扱う
遅延評価をサポート
dev toolsを開けば実行できるようになっている
ざっくりAPI
List, Stack, Map, OrderdMap, Set, OrderedSet. など
Record
でクラスと同じような使い方ができる(?)
Seq
遅延評価のための型
fromJS()
, toJS()
で普通のjsとの変換ができる
コストはかかる
まずは何から触ればいい?
List: 配列っぽいやつ
JavaScript// 使わない
const list1 = [1, 2, 3];
const list2 = list1;
list2.push(4);
list1 // [1, 2, 3, 4] ← 変わってる
list2 // [1, 2, 3, 4]
// 使う
const { List } = require('immutable@4.0.0-rc.9');
const list1 = List([ 1, 2, 3 ]);
const list2 = list1.push(4);
list1; // [1, 2, 3]
list2; // [1, 2, 3, 4]
Map: Objectっぽいやつ
JavaScript// immutable.jsを使わないパターン
const dmap1 = {a: 1, b: 2, c: 3};
const dmap2 = dmap1;
dmap2['a'] = 100;
dmap1['a']; // 100 ← 変わってる
dmap2['a']; // 100
// immutable.jsを使うパターン
const { Map } = require("immutable");
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('a', 100);
map1.get('a'); // 1
map2.get('a'); // 100
// TypeScriptでimmutable.jsを使う
import Immutable from require('immutable');
const map1: Immutable.Map<string, number> = Immutable.Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('a', 100);
map1.get('a'); // 1
map2.get('a'); // 100
Record: Interfaceみたいなやつ
中にはプロパティやメソッドを書く
Interfaceとは違い、型ではなく初期値を入れる
継承してクラスを作る
JavaScript const PersonRecord = Immutable.Record({
// 初期値
name: 'tarou',
age: 20
});
class Person extends PersonRecord {
public getName() {
return this.name;
}
public getAge() {
return this.age;
}
}
const person = new Person();
const name = person.getName();
const age = person.getAge();
console.log(name);
console.log(age);
メリット
パフォーマンス改善
なんで?
デメリット
一度入れたら途中でやめられない
updateって一つの項目ずつ更新するん?
jshoge = {
piyo: {
circles: ['茶道', 'ぷろぐらみんぐ'],
age: 23
}
}
みたいなデータのcirclesもageも更新したいときって
jshoge.updateIn(['piyo', 'circles'], c => {circleの更新処理})
.updateIn(['piyo', 'age'], a => a-1)
それとも以下のようにやるのか
できるのか?
jshoge.update('piyo', piyo => { 両方の更新処理 } )
hoge()
と hogeIn()
の違い
hoge()
hogeIn(['prop1', 'prop2',..], l => update(l))
入れ子になっているデータ構造にアクセスするときは hogeIn()
を使う(?)
第一引数でそのオブジェクトのプロパティを指定して、そこに対して第二引数の関数を適用する
配列の中でプロパティを指定するのがちょっと異質だが、要するに
通常のJSで hoge.piyo.foo
とアクセスしているのを、
['hoge','piyo','foo']
としてアクセスしている
jshogepiyo.getIn(['hoge', 'piyo', 'foo']); // => 6
const hogepiyo2 = hogepiyo.updateIn(['hoge', 'piyo', 'foo'], v => v + 1);
// => Map { hoge: Map { piyo: Map { foo: 7 } } }
keyが一致
簡単
tsconst newPost = postModel.updateIn(
['posts', postId, 'comments'], // `postId`をkeyで探している
() => comments
);
値が一致
findIndex
を使う
なぜかドキュメントにない
tsconst targetIndex = comments.findIndex(c => c.commentId === commentId);
const comments = comments.remove(targetIndex);
参考
Immutable.jsで値が一致したものを削除、などの操作をしたいとき
withMutationsとは
ふつうにやったら
jslet b = a.set(...)
b = b.update(...)
b = b.update(...)
とか
jslet b = a.set(...).update(...).update(...)
とかなるが、
とかやって毎回毎回値を返して更新するが
jslet b = withMutations(a => a.set(...).update(...).update(...)
とやるとパフォーマンス的に良いらしい
toJS()
するとそのプロパティの型が全部anyになるのをちゃんとしたい
fromJS
toJSの逆の概念
React + Immutable.js