@dsivd/prestations-ng 19.2.0-beta.14 → 19.2.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -338,7 +338,7 @@ It's the most telling example to show the team: **the signal drives the user inp
|
|
|
338
338
|
|
|
339
339
|
### `rxResource()` — asynchronous calls driven by a signal, with loading/error state included
|
|
340
340
|
|
|
341
|
-
An alternative to `toSignal()` when you also want state tracking (loading, error, reload) without coding it by hand. `rxResource()` accepts an `Observable` as data source, and is triggered again automatically when the signals
|
|
341
|
+
An alternative to `toSignal()` when you also want state tracking (loading, error, reload) without coding it by hand. `rxResource()` accepts an `Observable` as data source, and is triggered again automatically when the signals read by its `params` function change.
|
|
342
342
|
|
|
343
343
|
```ts
|
|
344
344
|
import { rxResource } from '@angular/core/rxjs-interop';
|
|
@@ -346,8 +346,8 @@ import { rxResource } from '@angular/core/rxjs-interop';
|
|
|
346
346
|
readonly userId = input.required<string>();
|
|
347
347
|
|
|
348
348
|
readonly userResource = rxResource({
|
|
349
|
-
|
|
350
|
-
|
|
349
|
+
params: () => this.userId(),
|
|
350
|
+
stream: ({ params: id }) => this.userService.getUser(id), // Observable<User>
|
|
351
351
|
});
|
|
352
352
|
|
|
353
353
|
// in the template: userResource.value(), userResource.isLoading(), userResource.error()
|
|
@@ -373,8 +373,8 @@ ngOnInit(): void {
|
|
|
373
373
|
```ts
|
|
374
374
|
// 🟢 After: rxResource(), loading/error included, automatic re-fetch if userId() changes
|
|
375
375
|
readonly userResource = rxResource({
|
|
376
|
-
|
|
377
|
-
|
|
376
|
+
params: () => this.userId(),
|
|
377
|
+
stream: ({ params: id }) => this.userService.getUser(id),
|
|
378
378
|
});
|
|
379
379
|
// userResource.value(), userResource.isLoading(), userResource.error()
|
|
380
380
|
```
|
|
@@ -423,6 +423,50 @@ The `async` pipe stays fully legitimate when the `Observable` is consumed **only
|
|
|
423
423
|
|
|
424
424
|
It also applies between layers: a service can compose entirely in RxJS (`debounceTime`, `retry`, `combineLatest`...) and stay testable independently of any component — it's the consuming component, "at the edge", that converts to a signal when displaying.
|
|
425
425
|
|
|
426
|
+
### And the `BehaviorSubject`s?
|
|
427
|
+
|
|
428
|
+
> 🎤 a `BehaviorSubject` holds a current value like a signal, but it is also a stream: we don't convert them systematically, we look at what it represents and who consumes it.
|
|
429
|
+
|
|
430
|
+
It becomes a `signal()` when it is a **private state**, written with `next()` and read with `getValue()` or `| async`, without any operator behind it:
|
|
431
|
+
|
|
432
|
+
```ts
|
|
433
|
+
// 🔴 A state kept in a BehaviorSubject
|
|
434
|
+
private readonly selectedTab = new BehaviorSubject<Tab>('summary');
|
|
435
|
+
|
|
436
|
+
// 🟢 The same state in a signal: readable in a computed(), no subscription
|
|
437
|
+
private readonly selectedTab = signal<Tab>('summary');
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
It stays in RxJS when:
|
|
441
|
+
|
|
442
|
+
- it is the **source of an RxJS chain** (`switchMap` to an HTTP call, `debounceTime`, `combineLatest`...): as a signal, it would have to go back through `toObservable()`, which emits later (through an `effect()`) and only the last value of several writes in a row. A useless round trip, and the timing changes
|
|
443
|
+
- it carries **events**, not a state: a signal ignores a value equal to the current one (`Object.is`) and merges the writes in a row
|
|
444
|
+
- it is part of the **public API** of a library or a shared service: replacing the `Observable` breaks its consumers. If they need a signal, add one next to it (`toSignal()` in the service) rather than replacing it
|
|
445
|
+
- some code relies on the **synchronous notification**: `subscribe()` is called at each `next()`, right away, whereas an `effect()` runs later, once for several writes
|
|
446
|
+
|
|
447
|
+
```ts
|
|
448
|
+
// 🔴 An event turned into a signal: the second reload triggers nothing
|
|
449
|
+
private readonly reloadTrigger = signal(true);
|
|
450
|
+
|
|
451
|
+
reload(): void {
|
|
452
|
+
this.reloadTrigger.set(true); // same value as before: no notification
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// 🟢 An event stays a stream: each next() counts
|
|
456
|
+
private readonly reloadTrigger = new Subject<void>();
|
|
457
|
+
|
|
458
|
+
readonly alerts$ = this.reloadTrigger.pipe(
|
|
459
|
+
startWith(undefined),
|
|
460
|
+
switchMap(() => this.alertService.getAlerts()),
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
reload(): void {
|
|
464
|
+
this.reloadTrigger.next();
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
> ⚠️ In a zoneless application, the `BehaviorSubject` itself is not the problem: a `subscribe()` writing a field read by the template, without notifying Angular, is. Fix the consumer with `toSignal()` or `| async` (see "Displaying an asynchronous state" in [GOOD_PRACTICES.md](GOOD_PRACTICES.md)).
|
|
469
|
+
|
|
426
470
|
---
|
|
427
471
|
|
|
428
472
|
## 7. Pitfall #1: mutation vs reassignment
|
|
@@ -501,3 +545,4 @@ export class ContactListComponent {
|
|
|
501
545
|
- I never mutate a signal value in place anymore — always `.set()`/`.update()` with a new reference
|
|
502
546
|
- I know when to use `untracked()` in an `effect()`
|
|
503
547
|
- I don't try to replace all my RxJS with signals — I keep RxJS for composed async (HTTP, debounce, switchMap...) and I only convert to a signal at the edge, with `toSignal()`/`toObservable()`/`rxResource()`
|
|
548
|
+
- I only turn a `BehaviorSubject` into a signal when it is a private state without operators — the sources of RxJS chains, the events and the public APIs stay in RxJS
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ng-update": {
|
|
40
40
|
"migrations": "./schematics/migration-collection.json"
|
|
41
41
|
},
|
|
42
|
-
"version": "19.2.0-beta.
|
|
42
|
+
"version": "19.2.0-beta.15",
|
|
43
43
|
"module": "fesm2022/dsivd-prestations-ng.mjs",
|
|
44
44
|
"typings": "types/dsivd-prestations-ng.d.ts",
|
|
45
45
|
"exports": {
|