Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7d474c5

Browse filesBrowse files
committed
docs(state): selection
1 parent 94d8b02 commit 7d474c5
Copy full SHA for 7d474c5

File tree

3 files changed

+114
-30
lines changed
Filter options

3 files changed

+114
-30
lines changed

‎libs/state/selections/README.md

Copy file name to clipboardExpand all lines: libs/state/selections/README.md
+11-4Lines 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

Copy file name to clipboardExpand all lines: libs/state/selections/docs/Readme.md
+71-4Lines 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

Copy file name to clipboardExpand all lines: libs/state/selections/src/lib/smosh.ts
+32-22Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.