When you have an array of objects, it often happens that you are interested on a particular entity based on some identifier, regardless of its position within the array:
1linkimport { state } from 'rxdeep';
2link
3linkconst s = state([
4link { id: 101, name: 'Jack', age: 32 },
5link { id: 102, name: 'Jill', age: 67 },
6link ...
7link]);
In this example, you might want a reactive state object that reflects state of Jack, independent
of where Jack sits in the array. The keyed()
method (or KeyedState
class) allows you to track entities of an array
using some key function which helps identify each entitiy:
1linkimport { state, keyed } from 'rxdeep';
2link
3linkconst k = keyed(state([
4link { id: 101, name: 'Jack', age: 32 },
5link { id: 102, name: 'Jill', age: 67 },
6link ...
7link ]),
8link person => person.id
9link);
10link
11linkk.key(101).subscribe(console.log);
In this example, the key function is person => person.id
, i.e. each person is identified
by their .id
property. .key()
method behaves like State.sub()
method, except that it represents
state of the entity matching given key instead of the entity on given index / property:
1linkk.value = [{ id: 103, name: 'James', age: 21 }, // --> no changes
2link ...state.value]; // --> no changes
3linkk.value = [{ id: 103, name: 'James', age: 21}, // --> no changes
4link { id: 101, name: 'Jack', age: 32 }]; // --> no changes
5linkk.value = [{ id: 101, name: 'Jack', age: 33 }]; // --> change!!
6link
7link// Logs only for the initial value and the last change:
8link// > { id: 101, name: 'Jack', age: 32 }
9link// > { id: 101, name: 'Jack', age: 33 }
The .key()
method returns a typical State
, so you can similarly
use them to set values:
1linkk.key(101).sub('age').value = 34;
2link
3link// Logs:
4link// > { id: 101, name: 'Jack', age: 34 }
touch_app NOTE
Similar to a sub-state, it is highly recommended to keep a keyed substate (result of
.key()
method) subscribed (having called its.subscribe()
method) before issueing changes to it, to ensure that the state is in sync with the change history.
info NOTE
Also you could use
KeyedState
constructor for creating keyed states:
1linkconst k = new KeyedState(new State(...), ...);
You can also track the index of a particular key within the array using .index()
method:
1linkimport { keyed, state } from 'rxdeep';
2link
3linkconst k = keyed(state([
4link { id: 101, name: 'Jack', age: 32 },
5link { id: 102, name: 'Jill', age: 67 },
6link ]),
7link person => person.id
8link);
9link
10linkk.index(101).subscribe(console.log);
11link
12linkk.value = [{ id: 103, name: 'James', age: 21 },
13link ...state.value];
14linkk.value = [{ id: 103, name: 'James', age: 21},
15link { id: 101, name: 'Jack', age: 32 }];
16linkk.value = [{ id: 101, name: 'Jack', age: 33 }];
17link
18link// Logs:
19link// > 0
20link// > 1
21link// > 0
The KeyedState
class also comes with .changes()
method which provides a detailed change
profile of the array in terms of additions, deletions and moved items:
1linkimport { state, keyed } from '../src';
2link
3linkconst k = keyed(state([
4link { id: 101, name: 'Jack', age: 32 },
5link { id: 102, name: 'Jill', age: 67 },
6link ]),
7link person => person.id
8link);
9link
10linkk.changes().subscribe(console.log);
11link
12linkk.value = [{ id: 103, name: 'James', age: 21 },
13link ...k.value];
14link// Logs:
15link// > {
16link// > additions: [{index: 0, item: {id: 103, name: 'James', age: 21}}],
17link// > deletions: [],
18link// > moves: [
19link// > {oldIndex: 0, newIndex: 1, item: {id: 101, name: 'Jack', age: 32}},
20link// > {oldIndex: 1, newIndex: 2, item: {id: 102, name: 'Jill', age: 67}}
21link// > ]
22link// > }
23link
24linkk.value = [{ id: 103, name: 'James', age: 21}, // --> no changes
25link { id: 101, name: 'Jack', age: 32 }]; // --> no changes
26link// Logs:
27link// > {
28link// > additions: [],
29link// > deletions: [{index: 2, item: {id: 102, name: 'Jill', age: 67}}],
30link// > moves: []
31link// > }
32link
33linkk.value = [{ id: 101, name: 'Jack', age: 33 }]; // --> change!!
34link// Logs:
35link// > {
36link// > additions: [],
37link// > deletions: [{index: 0, item: {id: 103, name: 'James', age: 21}}],
38link// > moves: [{oldIndex: 1, newIndex: 0, item: {id: 101, name: 'Jack', age: 32}}]
39link// > }
40link
41linkk.key(101).sub('age').value = 34;
42link// Logs:
43link// > {
44link// > additions: [],
45link// > deletions: [],
46link// > moves: []
47link// > }