Introduction into the Immutable js


統計学が一段落したので、ちょこちょこ React 書いてます。
flux-utils に immutable js を導入してみています。

Record 型の導入は flow と併用するとなかなか面倒くさいと聞いていたので、現状は immutable object を props/state に持ち込んでいる段階です。


ValueObject()

Immutable Object を Set 内もしくは Map の Key として持つと、それは ValueObject と定義できる。

const a = List([ 1, 2, 3 ]);
const b = List([ 1, 2, 3 ]);
assert(a !== b); // different instances
const set = Set([ a ]);
assert(set.has(b) === true);

これはまだ使っていない。

List()

/* class definition */
class List<T> extends Collection.Indexed<T>
/* initialize */
List(): List<any>
List<T>(): List<T>
List<T>(collection: Iterable<T>): List<T>

慣れが必要だったのは、interface が x[0] から x.get(0) に変わることと、forEach で block 内返り値が false になってはいけない点かな。nested obj の扱いは非常に気持ちいい。

Map()

引数をネストした時は value 値が Immutable Object の型に取られるっぽい

/* class definition */
class Map<K, V> extends Collection.Keyed<K, V>
/* initialize */
Map<K, V>(collection: Iterable<[K, V]>): Map<K, V>
Map<T>(collection: Iterable<Iterable<T>>): Map<T, T>
Map<V>(obj: {[key: string]: V}): Map<string, V>
Map<K, V>(): Map<K, V>
Map(): Map<any, any>

Map 内 List element の更新が上手いことかけなかったのが残念。多分良い書き方があるんだろうから、誰かに教えてもらいたい。

x = Map('a': List( Map({ 'b': 1, 'c': 2 }) ) );
y = x.get('a').get(0);
z = x.set('a', List(y.set('b', 3)));
// => Map('a': List( Map({ 'b': 3, 'c': 2 }) ) )

is(arg1:any, arg2:any):boolean

Object.is() と異なり、Immutable Object を引数に渡しても k/v 含めた同値判定を行ってくれる。

componentShouldUpdate() で同値判定してやって、パフォーマンス・チューニングする際に使うのかなと思っている。実際には使っていない。

isImmutable(arg1:any):boolean

引数が maybeImmutable Object か判定してくれる。
ex. Map(), List(), Stack()

汎用 component 内で使っている。Array / List どちらも受けうる時に、if (isImmutable(xx) ) {} と言った感じで escape できる。

isCollection(arg1:any):boolean

引数が maybeCollection か判定してくれる。
ex. Map(), List(), Stack()

isImmutable との使い分け方がわかっていないので使っていない。

isKeyed(arg1:any):boolean

引数が maybeKeyed か判定してくれる。
ex. Map()

個人開発ではデータの流れが把握できているので必要ないが、チーム開発時にはありがたいのかも。ただ immutable record まで導入してしまえば、基本的には不要なのではないかと感じている。Map / List 共に受けうるユースケースに出会ってないだけかも。

isIndexed(arg1:any):boolean

引数が maybeIndexed か判定してくれる。
ex. List(), Stack()

maybeAssociative(arg1:any):boolean

引数が maybeKeyed || maybeIndexed か判定してくれる。
ex. Map(), List(), Stack()

isOrdered(arg1:any):boolean

引数が Immutable.indexed か判定してくれる。
ex. List(), OrderedMap(), OrderedSet()

isValueObject(arg1:any):boolean

引数が valueObject か判定してくれる。


チーム開発で使ってみるとまた印象も変わるイメージ。
server 側に immutable obj のまま ( {value: Map(k,v)} ) state を渡せるので、型変換を行うのは server 側からデータを受ける action のみ。

component 内での obj 処理は update-util を利用するよりも圧倒的に簡潔に書けるのは嬉しかったかな。

  • action: 
    In: js obj
    Out: immutable obj
  • store: 
    In: immutable obj
    Out: immutable obj
  • Container:
    In: immutable obj
    Out: immutable obj
  • Component:
    In: immutable obj
    Out: immutable obj

もうしばらく書いてみます。

よしなに