Skip to content

Commit 151d7f2

Browse files
timdeschryvermarkostanimirovicrainerhahnekamp
authored
docs(eslint-plugin): add docs for no-store-subscription (#5075)
Co-authored-by: Marko Stanimirović <[email protected]> Co-authored-by: Rainer Hahnekamp <[email protected]>
1 parent dc3d8fa commit 151d7f2

File tree

1 file changed

+62
-10
lines changed

1 file changed

+62
-10
lines changed

projects/www/src/app/pages/guide/eslint-plugin/rules/no-store-subscription.md

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,87 @@ Using the `async` pipe is preferred over `store` subscription.
1313

1414
## Rule Details
1515

16+
This rule prevents manual subscriptions to the store, which can lead to memory leaks if not properly unsubscribed. Using the `async` pipe is the recommended approach because Angular automatically handles the subscription and unsubscription, keeping your component code cleaner and preventing memory leaks.
17+
18+
### Why Avoid Store Subscriptions?
19+
20+
⚠️ **Problems with manual store subscriptions:**
21+
22+
- Creates a manual subscription that must be explicitly unsubscribed (e.g., using `takeUntil`, `async`, or `destroyRef`), otherwise it will persist beyond the component's lifecycle causing memory leaks
23+
Will not trigger change detection in zoneless mode. Users have to ensure it otherwise.
24+
25+
**Benefits of using the async pipe:**
26+
27+
- No manual subscription management - Angular's `async` pipe handles subscription and unsubscription automatically
28+
- Keeps the component more declarative
29+
1630
Examples of **incorrect** code for this rule:
1731

32+
1. Subscribing to the store to get data from a selector
33+
1834
<ngrx-code-example>
1935

2036
```ts
2137
ngOnInit() {
22-
this.store.select(selectedItems).subscribe(items => {
23-
this.items = items;
38+
this.store.select(selectedProduct).subscribe(product => {
39+
this.product = product;
2440
})
2541
}
2642
```
2743

2844
</ngrx-code-example>
2945

46+
2. Subscribing to the store for side effects
47+
48+
<ngrx-code-example>
49+
50+
```ts
51+
ngOnInit() {
52+
this.subscription = this.store
53+
.select(selectAuthenticatedUserState)
54+
.subscribe(state => {
55+
this.busy = state.busy;
56+
if (state.authenticated) {
57+
this.router.navigateByUrl('/');
58+
}
59+
});
60+
}
61+
```
62+
63+
</ngrx-code-example>
64+
3065
Examples of **correct** code for this rule:
3166

32-
<!-- prettier-ignore -->
67+
1. Using the `async` pipe to get data from a selector
68+
3369
<ngrx-code-example>
3470

3571
```ts
3672
// in code
37-
selectedItems$ = this.store.select(selectedItems);
73+
selectedProduct$ = this.store.select(selectedProduct);
3874

39-
// in template
40-
{
41-
{
42-
selectedItems$ | async;
43-
}
44-
}
75+
// in the template
76+
<product-details [product]="selectedProduct$ | async"></product-details>
77+
```
78+
79+
</ngrx-code-example>
80+
81+
2. Consider using an effect for side effects
82+
83+
<ngrx-code-example>
84+
85+
```ts
86+
redirectIfAuthenticated$ = createEffect(
87+
() => {
88+
return this.store.select(selectAuthenticatedUserState).pipe(
89+
filter(state => state.authenticated),
90+
tap(() => {
91+
this.router.navigateByUrl('/');
92+
})
93+
);
94+
},
95+
{ dispatch: false }
96+
);
4597
```
4698

4799
</ngrx-code-example>

0 commit comments

Comments
 (0)