Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7d474c5

Browse files
committed
docs(state): selection
1 parent 94d8b02 commit 7d474c5

File tree

3 files changed

+114
-30
lines changed

3 files changed

+114
-30
lines changed

libs/state/selections/README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,23 @@
66

77
## Slogan
88

9-
`@rx-angular/state/selections` TBD
9+
`@rx-angular/state/selections` provides performant and boiler plate free helpers for to craft custom selections with just a few lines of code.
1010

1111
## Key features
1212

13-
-
13+
- ✅ reduces repetitative code to a minimum
14+
- ✅ most common problems solved with a 1 liner
15+
- ✅ distinct values
16+
- ✅ lazy initialization (avoids `?` in the template)
17+
- ✅ shared computation
18+
- ✅ strongly types
19+
- ✅ fully tested
20+
21+
1422

1523
## Demos:
1624

17-
- ⚡ GitHub
25+
- ⚡ GitHub Todo
1826

1927
## Install
2028

@@ -27,4 +35,3 @@ yarn add @rx-angular/state
2735
## Documentation
2836

2937
- [Selections](https://github.com/rx-angular/rx-angular/tree/main/libs/state/selections/docs/Readme.md)
30-

libs/state/selections/docs/Readme.md

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,16 @@ As this process contains a lot of gotchas and possible pitfalls in terms of memo
5959
- Shares computed result with multiple subscriber
6060
- Select distinct sub-sets
6161
- Select from static values
62-
- Fully Tested
63-
- Fully Typed
62+
- Fully tested
63+
- Strongly typed
6464

65-
## Selection owner - Template vs Class
65+
# Concepts
66+
67+
## Selection composition - lazy vs eager
68+
69+
## Selection composition - functional vs reactive
70+
71+
## Selection setup - Template vs Class
6672

6773
As Observables are cold their resulting stream will only get activated by a subscription.
6874
This leads to a situations called: "the late subscriber problem" or "the early subscriber problem". (LINK)
@@ -74,8 +80,69 @@ In most cases it's best to go with solving problems on the early subscriber side
7480

7581
![Selections (4)](https://user-images.githubusercontent.com/10064416/152422883-0b5f6006-7929-4520-b0b2-79eb61e4eb08.png)
7682

83+
# Usage
84+
85+
## select
86+
87+
`select` is the stand-alone version of the `RxState#select` top level method. It helps to create default selection's from a changing state source.
88+
89+
```typescritp
90+
// emissions:
91+
// 0. - no emission ever happened
92+
// 1. {a: 1} - incomplete state leads to `?` pollution in the template
93+
// 2. {a: 1, b: 'a'} - render relevant emission
94+
// 2. {a: 1, b: 'a'} - same instance emisssion
95+
// 3. {a: 1, b: 'a', c: true} - render irrelevant change
96+
// 4. {a: 1, b: 'b', c: true} - render relevant emission
97+
const model$: Observable<Partial<{a: number, b: string, c: boolean}>>;
98+
```
99+
**Problem**
100+
```html
101+
<!--
102+
103+
Computes 2 times & Renders 0. ❌; 1. ❌; 2. ✅; 3. ❌; .4 ✅
104+
-->
105+
<div *rxLet="model$; let vm">
106+
B: {{vm?.b}}
107+
</div>
108+
B: {{(model$ | push)?.b}}
109+
```
110+
111+
### single property short hand
112+
```typescritp
113+
const vm$ = model$.pipe(select('b'));
114+
```
115+
```html
116+
<!--
117+
Computes 1 time & Renders 2. ✅; .4 ✅
118+
-->
119+
<div *rxLet="model$; let vm">
120+
B: {{vm.b}}
121+
</div>
122+
B: {{(model$ | push).b}}
123+
```
124+
125+
### single operators
126+
```typescritp
127+
const vm$: Observable<> = model$.pipe(select(map(({b}) => b === 'a')));
128+
```
129+
```html
130+
<!--
131+
Computes 1 time & Renders 2. ✅; .4 ✅
132+
-->
133+
<div *rxLet="model$; let vm">
134+
B: {{vm.b}}
135+
</div>
136+
B: {{(model$ | push).b}}
137+
```
138+
139+
## selectSlice
140+
141+
## smosh
142+
143+
## distinctUntilSomeChanges
77144

78-
## Advanced derivation architecture
145+
# Advanced derivation architecture
79146

80147
**The problem**
81148

libs/state/selections/src/lib/smosh.ts

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,15 @@ const resolvedPromise$ = from(resolvedPromise);
4646
* @param obj - An object of key & Observable values pairs
4747
* @param durationSelector - An Observable determining the duration for the internal coalescing method
4848
*/
49-
export function smosh<T extends ObservableMap | (Partial<T> & NotEmpty<T>), U extends Record<string, any>>(
49+
export function smosh<
50+
T extends ObservableMap | (Partial<T> & NotEmpty<T>),
51+
U extends Record<string, any>
52+
>(
5053
obj: Partial<T>,
5154
spreads: Observable<U>[] = [],
52-
options?: {durationSelector: Observable<any>}
53-
): Observable<{ [K in keyof T]: ExtractObservableValue<T[K]>} & U> {
54-
let {durationSelector} = options || {};
55+
options?: { durationSelector: Observable<any> }
56+
): Observable<{ [K in keyof T]: ExtractObservableValue<T[K]> } & U> {
57+
let { durationSelector } = options || {};
5558
durationSelector = durationSelector || resolvedPromise$;
5659
const keys = Object.keys(obj) as (keyof T)[];
5760
const observables = keys.map((key) =>
@@ -73,25 +76,32 @@ export function smosh<T extends ObservableMap | (Partial<T> & NotEmpty<T>), U ex
7376
}
7477
return obj;
7578
})
76-
)
77-
spreads = spreads.map(o => o.pipe(
78-
// we avoid using the nullish operator later ;)
79-
filter((v) => v !== undefined),
80-
// state "changes" differ from each other, this operator ensures distinct values
81-
distinctUntilChanged()
79+
);
80+
spreads = spreads.map((o) =>
81+
o.pipe(
82+
// we avoid using the nullish operator later ;)
83+
filter((v) => v !== undefined),
84+
// state "changes" differ from each other, this operator ensures distinct values
85+
distinctUntilChanged()
8286
)
8387
);
8488

85-
return merge(...spreads, obj$).pipe(scan((acc, slice) => {
86-
const ks = Object.keys(slice) as (keyof T)[];
87-
for (let i = 0; i < ks.length; i++) {
88-
acc[ks[i] as any] = slice[ks[i]];
89-
}
90-
return acc as any;
91-
}, {})).pipe(
92-
// As combineLatest will emit multiple times for a change in multiple properties we coalesce those emissions together
93-
coalesceWith(durationSelector),
94-
// by using shareReplay we share the last composition work done to create the accumulated object
95-
shareReplay(1)
96-
);
89+
return combineLatest([...spreads, obj$])
90+
.pipe(
91+
scan((acc, slices) => {
92+
const ks = slices.flatMap((slice) => Object.keys(slice)) as (keyof T)[];
93+
slices.forEach((slice) => {
94+
for (let i = 0; i < ks.length; i++) {
95+
acc[ks[i] as any] = slice[ks[i]];
96+
}
97+
});
98+
return acc as any;
99+
}, {})
100+
)
101+
.pipe(
102+
// As combineLatest will emit multiple times for a change in multiple properties we coalesce those emissions together
103+
coalesceWith(durationSelector),
104+
// by using shareReplay we share the last composition work done to create the accumulated object
105+
shareReplay(1)
106+
);
97107
}

0 commit comments

Comments
 (0)