Skip to content

Commit e9219d1

Browse files
authored
docs: create v21 announcement article (#2390)
1 parent 05cbecf commit e9219d1

File tree

1 file changed

+158
-0
lines changed
  • publication/2025-12-17_announcing_ngxs_21

1 file changed

+158
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Announcing NGXS v21
2+
3+
We are excited to announce the release of NGXS v21, our latest major version of the state management library for Angular! This release introduces a powerful new feature for managing asynchronous action lifecycles, along with important bug fixes and performance improvements to help you build more robust Angular applications.
4+
5+
For a complete list of changes, see our [v21.0.0 changelog entry](https://github.com/ngxs/store/blob/master/CHANGELOG.md#2100-2025-12-17).
6+
7+
## Overview
8+
9+
- 🎯 [AbortSignal Support for Action Handlers](#abortsignal-support) ([PR #2244](https://github.com/ngxs/store/pull/2244))
10+
- 🐛 [Bug Fixes and Stability Improvements](#bug-fixes)
11+
- 🔌 [Plugin Improvements](#plugin-improvements)
12+
13+
---
14+
15+
## AbortSignal Support
16+
17+
One of the most exciting features in this release is the addition of `AbortSignal` support on the state context. This provides a standardized way to handle cancellation of asynchronous operations in your action handlers ([PR #2244](https://github.com/ngxs/store/pull/2244)).
18+
19+
### Why AbortSignal?
20+
21+
When working with asynchronous actions, especially those marked with `cancelUncompleted: true`, you may need to gracefully handle cancellation when a new action is dispatched before the previous one completes. The `AbortSignal` provides a standard browser API to detect and respond to these cancellations.
22+
23+
### How to Use It
24+
25+
The `StateContext` now includes an `abortSignal` property that you can use in your action handlers:
26+
27+
```ts
28+
import { Injectable } from '@angular/core';
29+
import { State, Action, StateContext } from '@ngxs/store';
30+
31+
export class FetchCountries {
32+
static readonly type = '[Countries] Fetch';
33+
}
34+
35+
@State<string[]>({
36+
name: 'countries',
37+
defaults: []
38+
})
39+
@Injectable()
40+
export class CountriesState {
41+
@Action(FetchCountries, { cancelUncompleted: true })
42+
async fetchCountries(ctx: StateContext<string[]>) {
43+
// Simulate some async work
44+
await new Promise(resolve => setTimeout(resolve, 100));
45+
46+
// Check if the action was canceled before updating state
47+
if (ctx.abortSignal.aborted) {
48+
console.log('Action was canceled, skipping state update');
49+
return;
50+
}
51+
52+
ctx.setState(['USA', 'Canada', 'Mexico']);
53+
}
54+
}
55+
```
56+
57+
### Integration with Fetch API
58+
59+
The `AbortSignal` works seamlessly with modern browser APIs like `fetch`:
60+
61+
```ts
62+
@Action(FetchUsers, { cancelUncompleted: true })
63+
async fetchUsers(ctx: StateContext<User[]>) {
64+
try {
65+
// Pass the abort signal directly to fetch
66+
const response = await fetch('/api/users', {
67+
signal: ctx.abortSignal
68+
});
69+
70+
const users = await response.json();
71+
ctx.setState(users);
72+
} catch (error) {
73+
if (error.name === 'AbortError') {
74+
console.log('Fetch was canceled');
75+
return;
76+
}
77+
throw error;
78+
}
79+
}
80+
```
81+
82+
### Key Benefits
83+
84+
- **Standardized API**: Uses the browser's native `AbortSignal` API, making it familiar and compatible with other web APIs
85+
- **Graceful Cancellation**: Allows you to clean up resources and avoid unnecessary state updates when actions are canceled
86+
- **Better Performance**: Prevents wasted work by detecting cancellation early in your async operations
87+
- **Observable Auto-unsubscribe**: When using observables, they are automatically unsubscribed when the signal is aborted
88+
89+
## Bug Fixes
90+
91+
We've addressed several important issues to improve stability and reliability:
92+
93+
- **Lifecycle Safety**: Added guards against running state functions after the injector is destroyed ([PR #2366](https://github.com/ngxs/store/pull/2366), [PR #2377](https://github.com/ngxs/store/pull/2377))
94+
- **Selector Improvements**: Fixed `createPickSelector` to not throw on unregistered states ([PR #2378](https://github.com/ngxs/store/pull/2378))
95+
- **Application Stability**: Stopped contributing to stability once the app is stable, improving performance ([PR #2379](https://github.com/ngxs/store/pull/2379))
96+
- **Type Safety**: Updated action handler types to allow `Observable<unknown>` and `Promise<unknown>` ([PR #2385](https://github.com/ngxs/store/pull/2385))
97+
- **Task Management**: Fixed issue where tasks could cause unnecessary unsubscribe operations ([PR #2388](https://github.com/ngxs/store/pull/2388))
98+
99+
## Performance Improvements
100+
101+
This release includes several performance optimizations:
102+
103+
- **Memory Management**: Cleared internal `_states` on destroy to aid garbage collection under high load ([PR #2365](https://github.com/ngxs/store/pull/2365))
104+
- **Signal Debugging**: Added `debugName` to computed signals in `selectSignal` for better developer experience ([PR #2370](https://github.com/ngxs/store/pull/2370))
105+
106+
## Plugin Improvements
107+
108+
### Storage Plugin
109+
110+
- **Null Safety**: Added guards to prevent errors when storage engine may be falsy ([PR #2367](https://github.com/ngxs/store/pull/2367), [PR #2368](https://github.com/ngxs/store/pull/2368))
111+
- **Performance**: Replaced closure-based action matcher with direct type comparison for better performance ([PR #2369](https://github.com/ngxs/store/pull/2369))
112+
113+
### Router Plugin
114+
115+
- **State Update Optimization**: Avoids redundant NGXS state updates for identical router snapshots ([PR #2372](https://github.com/ngxs/store/pull/2372))
116+
117+
---
118+
119+
## Upgrading from v20
120+
121+
Upgrading to v21 should be straightforward for most applications. The main addition is the new `abortSignal` property on `StateContext`, which is additive and doesn't break existing code.
122+
123+
If you're using `cancelUncompleted` actions with async/await, we recommend adding `abortSignal` checks after await points to ensure your handlers gracefully handle cancellation:
124+
125+
```ts
126+
// Before
127+
@Action(MyAction, { cancelUncompleted: true })
128+
async myHandler(ctx: StateContext<MyState>) {
129+
await someAsyncWork();
130+
ctx.setState(newState); // May execute even if canceled
131+
}
132+
133+
// After (recommended)
134+
@Action(MyAction, { cancelUncompleted: true })
135+
async myHandler(ctx: StateContext<MyState>) {
136+
await someAsyncWork();
137+
if (ctx.abortSignal.aborted) return; // Gracefully exit if canceled
138+
ctx.setState(newState);
139+
}
140+
```
141+
142+
If you encounter any issues when upgrading, please check our [full documentation](https://www.ngxs.io/) first. Feel free to comment on the [discussion on GitHub](https://github.com/ngxs/store/discussions) if you believe there is an issue introduced by this release.
143+
144+
---
145+
146+
## Some Useful Links
147+
148+
If you would like any further information on changes in this release please feel free to have a look at our [changelog](https://github.com/ngxs/store/blob/master/CHANGELOG.md). The code for NGXS is all available at [https://github.com/ngxs/store](https://github.com/ngxs/store) and our docs are available at [https://www.ngxs.io/](https://www.ngxs.io/).
149+
150+
Helpful resources:
151+
152+
- [NGXS Concepts Documentation](https://www.ngxs.io/concepts)
153+
- [Action Cancellation Guide](https://www.ngxs.io/concepts/actions/cancellation)
154+
- [NGXS Plugins Documentation](https://www.ngxs.io/plugins)
155+
- [NGXS Recipes](https://www.ngxs.io/recipes)
156+
- [Github Repository](https://github.com/ngxs/store)
157+
158+
We have a thriving community on our Discord server so come and join us to keep abreast of the latest developments. Here is the Discord invitation link: [https://discord.gg/yT3Q8cXTnz](https://discord.gg/yT3Q8cXTnz)

0 commit comments

Comments
 (0)