0
# @ngrx/effects
1
2
NgRx Effects is a side effect model for @ngrx/store that provides RxJS-powered effect management for Angular applications. It allows for handling asynchronous operations and external interactions while maintaining separation of concerns between pure state logic and side effects.
3
4
## Package Information
5
6
- **Package Name**: @ngrx/effects
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @ngrx/effects`
10
11
## Core Imports
12
13
```typescript
14
import {
15
createEffect,
16
Actions,
17
ofType,
18
EffectsModule,
19
provideEffects,
20
mergeEffects,
21
getEffectsMetadata
22
} from "@ngrx/effects";
23
```
24
25
## Basic Usage
26
27
```typescript
28
import { Injectable } from "@angular/core";
29
import { Actions, createEffect, ofType } from "@ngrx/effects";
30
import { map, switchMap } from "rxjs/operators";
31
import { of } from "rxjs";
32
33
@Injectable()
34
export class UserEffects {
35
constructor(private actions$: Actions) {}
36
37
// Class-based effect
38
loadUsers$ = createEffect(() =>
39
this.actions$.pipe(
40
ofType(UserActions.loadUsers),
41
switchMap(() =>
42
this.userService.getUsers().pipe(
43
map(users => UserActions.loadUsersSuccess({ users })),
44
catchError(error => of(UserActions.loadUsersFailure({ error })))
45
)
46
)
47
)
48
);
49
}
50
51
// Functional effect
52
export const loadUsersEffect = createEffect(
53
(actions$ = inject(Actions)) =>
54
actions$.pipe(
55
ofType(UserActions.loadUsers),
56
switchMap(() =>
57
inject(UserService).getUsers().pipe(
58
map(users => UserActions.loadUsersSuccess({ users }))
59
)
60
)
61
),
62
{ functional: true }
63
);
64
```
65
66
## Architecture
67
68
NgRx Effects is built around several key components:
69
70
- **Effect Creation**: `createEffect()` function for defining effects with metadata
71
- **Action Stream**: `Actions` service providing access to all dispatched actions
72
- **Action Filtering**: `ofType()` operator for type-safe action filtering
73
- **Module Integration**: `EffectsModule` for module-based setup, `provideEffects()` for standalone apps
74
- **Lifecycle Management**: Hooks for controlling effect registration and execution
75
- **Error Handling**: Built-in error handling with retry mechanisms
76
- **Testing Support**: Mock providers and utilities for effect testing
77
78
## Capabilities
79
80
### Effect Creation and Management
81
82
Core functionality for creating and managing effects, including both class-based and functional patterns.
83
84
```typescript { .api }
85
function createEffect<
86
C extends EffectConfig & { functional?: false },
87
DT extends DispatchType<C>,
88
OTP,
89
R extends EffectResult<OT>,
90
OT extends ObservableType<DT, OTP>
91
>(
92
source: () => R & ConditionallyDisallowActionCreator<DT, R>,
93
config?: C
94
): R & CreateEffectMetadata;
95
96
function createEffect<Source extends () => Observable<unknown>>(
97
source: Source,
98
config: EffectConfig & { functional: true; dispatch: false }
99
): FunctionalEffect<Source>;
100
101
function createEffect<Source extends () => Observable<Action>>(
102
source: Source & ConditionallyDisallowActionCreator<true, ReturnType<Source>>,
103
config: EffectConfig & { functional: true; dispatch?: true }
104
): FunctionalEffect<Source>;
105
106
function createEffect<
107
Result extends EffectResult<unknown>,
108
Source extends () => Result
109
>(
110
source: Source,
111
config?: EffectConfig
112
): (Source | Result) & CreateEffectMetadata;
113
114
interface EffectConfig {
115
dispatch?: boolean;
116
functional?: boolean;
117
useEffectsErrorHandler?: boolean;
118
}
119
120
type DispatchType<T> = T extends { dispatch: infer U } ? U : true;
121
type ObservableType<T, OriginalType> = T extends false ? OriginalType : Action;
122
type EffectResult<OT> = Observable<OT> | ((...args: any[]) => Observable<OT>);
123
type ConditionallyDisallowActionCreator<DT, Result> = DT extends false
124
? unknown
125
: Result extends EffectResult<infer OT>
126
? OT extends ActionCreator
127
? 'ActionCreator cannot be dispatched. Did you forget to call the action creator function?'
128
: unknown
129
: unknown;
130
131
type FunctionalEffect<
132
Source extends () => Observable<unknown> = () => Observable<unknown>
133
> = Source & FunctionalCreateEffectMetadata;
134
135
interface FunctionalCreateEffectMetadata extends CreateEffectMetadata {
136
'__@ngrx/effects_create__': EffectConfig & { functional: true };
137
}
138
139
interface CreateEffectMetadata {
140
'__@ngrx/effects_create__': EffectConfig;
141
}
142
```
143
144
[Effect Creation and Management](./effect-creation.md)
145
146
### Actions and Filtering
147
148
Action stream management and type-safe action filtering capabilities.
149
150
```typescript { .api }
151
class Actions<V = Action> extends Observable<V> {
152
lift<R>(operator?: Operator<V, R>): Observable<R>;
153
}
154
155
function ofType<E extends Extract<A, { type: T }>, A extends Action = Action, T extends string = A['type']>(
156
...allowedTypes: [T, ...T[]]
157
): OperatorFunction<A, E>;
158
159
function ofType<AC extends ActionCreator<string, Creator>, U extends Action = Action>(
160
...allowedTypes: [AC, ...AC[]]
161
): OperatorFunction<U, ReturnType<AC>>;
162
```
163
164
[Actions and Filtering](./actions-filtering.md)
165
166
### Module Setup and Providers
167
168
Integration with Angular's module system and standalone applications.
169
170
```typescript { .api }
171
class EffectsModule {
172
static forRoot(effects: Type<any>[]): ModuleWithProviders<EffectsRootModule>;
173
static forFeature(effects: Type<any>[]): ModuleWithProviders<EffectsFeatureModule>;
174
}
175
176
function provideEffects(
177
effects: Array<Type<unknown> | Record<string, FunctionalEffect>>
178
): EnvironmentProviders;
179
180
function provideEffects(
181
...effects: Array<Type<unknown> | Record<string, FunctionalEffect>>
182
): EnvironmentProviders;
183
184
function mergeEffects(...effects: Array<Observable<Action> | (() => Observable<Action>)>): () => Observable<Action>;
185
186
function getEffectsMetadata<T extends Record<keyof T, Object>>(instance: T): EffectMetadata<T>[];
187
```
188
189
[Module Setup and Providers](./module-setup.md)
190
191
### Advanced Features
192
193
Lifecycle hooks, error handling, and advanced effect management capabilities.
194
195
```typescript { .api }
196
interface OnIdentifyEffects {
197
ngrxOnIdentifyEffects(): string;
198
}
199
200
interface OnRunEffects {
201
ngrxOnRunEffects(resolvedEffects$: Observable<EffectNotification>): Observable<EffectNotification>;
202
}
203
204
interface OnInitEffects {
205
ngrxOnInitEffects(): Action;
206
}
207
208
type EffectsErrorHandler = <T extends Action>(
209
observable$: Observable<T>,
210
errorHandler: ErrorHandler
211
) => Observable<T>;
212
213
function defaultEffectsErrorHandler<T extends Action>(
214
observable$: Observable<T>,
215
errorHandler: ErrorHandler,
216
retryAttemptLeft: number = 10
217
): Observable<T>;
218
```
219
220
[Advanced Features](./advanced-features.md)
221
222
### Testing Utilities
223
224
Testing support for effects with mock providers and utilities.
225
226
```typescript { .api }
227
function provideMockActions(source: Observable<any>): FactoryProvider;
228
function provideMockActions(factory: () => Observable<any>): FactoryProvider;
229
```
230
231
Import testing utilities:
232
```typescript
233
import { provideMockActions } from "@ngrx/effects/testing";
234
```
235
236
[Testing Utilities](./testing.md)
237
238
## Core Types
239
240
```typescript { .api }
241
interface Action {
242
type: string;
243
}
244
245
interface ActionCreator<T extends string = string, C extends Creator = Creator> {
246
readonly type: T;
247
(...args: any[]): any;
248
}
249
250
interface Creator {
251
(...args: any[]): object;
252
}
253
254
interface EffectNotification {
255
effect: Observable<any> | (() => Observable<any>);
256
propertyName: PropertyKey;
257
sourceName: string | null;
258
sourceInstance: any;
259
notification: ObservableNotification<Action | null | undefined>;
260
}
261
262
interface EffectSources {
263
addEffects(effectSourceInstance: any): void;
264
toActions(): Observable<Action>;
265
}
266
267
class EffectsRunner implements OnDestroy {
268
get isStarted(): boolean;
269
start(): void;
270
ngOnDestroy(): void;
271
}
272
273
interface OnDestroy {
274
ngOnDestroy(): void;
275
}
276
277
interface ObservableNotification<T> {
278
kind: 'N' | 'E' | 'C';
279
value?: T;
280
error?: any;
281
}
282
283
type EffectPropertyKey<T extends Record<keyof T, Object>> = Exclude<
284
keyof T,
285
keyof Object
286
>;
287
288
interface EffectMetadata<T extends Record<keyof T, Object>>
289
extends Required<EffectConfig> {
290
propertyName: EffectPropertyKey<T>;
291
}
292
293
type EffectsMetadata<T extends Record<keyof T, Object>> = {
294
[Key in EffectPropertyKey<T>]?: EffectConfig;
295
};
296
297
interface Type<T = any> {
298
new (...args: any[]): T;
299
}
300
301
interface ModuleWithProviders<T> {
302
ngModule: Type<T>;
303
providers?: any[];
304
}
305
306
interface EnvironmentProviders {
307
ɵproviders: any[];
308
}
309
310
interface FactoryProvider {
311
provide: any;
312
useFactory: (...args: any[]) => any;
313
deps?: any[];
314
}
315
316
interface InjectionToken<T> {
317
toString(): string;
318
}
319
320
interface Observable<T> {
321
pipe(...operations: any[]): Observable<any>;
322
subscribe(...args: any[]): any;
323
}
324
325
interface OperatorFunction<T, R> {
326
(source: Observable<T>): Observable<R>;
327
}
328
329
interface Operator<T, R> {
330
call(subscriber: any, source: Observable<T>): any;
331
}
332
```
333
334
## Constants and Tokens
335
336
```typescript { .api }
337
const ROOT_EFFECTS_INIT: "@ngrx/effects/init";
338
339
function rootEffectsInit(): Action;
340
341
const EFFECTS_ERROR_HANDLER: InjectionToken<EffectsErrorHandler>;
342
const USER_PROVIDED_EFFECTS: InjectionToken<Array<Type<unknown> | InjectionToken<unknown>>[]>;
343
const _ROOT_EFFECTS_GUARD: InjectionToken<void>;
344
const _ROOT_EFFECTS: InjectionToken<[Array<Type<unknown> | Record<string, FunctionalEffect>>]>;
345
const _ROOT_EFFECTS_INSTANCES: InjectionToken<unknown[]>;
346
const _FEATURE_EFFECTS: InjectionToken<Array<Type<unknown> | Record<string, FunctionalEffect>>[]>;
347
const _FEATURE_EFFECTS_INSTANCE_GROUPS: InjectionToken<unknown[][]>;
348
```