Consider an Angular effect that listens for an action and dispatches another action. What is the result in the application?
import { createEffect, ofType, Actions } from '@ngrx/effects'; import { Injectable } from '@angular/core'; import { map } from 'rxjs/operators'; import * as MyActions from './actions'; @Injectable() export class MyEffects { effect$ = createEffect(() => this.actions$.pipe( ofType(MyActions.loadData), map(() => MyActions.loadDataSuccess({ data: [1, 2, 3] })) )); constructor(private actions$: Actions) {} }
Think about what happens when an effect returns a new action.
Effects listen for specific actions and can dispatch new actions to update the store or trigger other effects. Here, the effect listens for 'loadData' and dispatches 'loadDataSuccess' with data.
Which option shows the correct syntax for creating an effect that does NOT dispatch an action?
import { createEffect, ofType, Actions } from '@ngrx/effects'; import { Injectable } from '@angular/core'; import { tap } from 'rxjs/operators'; import * as MyActions from './actions'; @Injectable() export class MyEffects { logEffect$ = createEffect(() => this.actions$.pipe( ofType(MyActions.loadData), tap(() => console.log('Load data action received')) ), { dispatch: false }); constructor(private actions$: Actions) {} }
Think about how to create effects that only perform side effects without dispatching new actions.
When an effect does not dispatch an action, you must set { dispatch: false } in createEffect options. Using tap is correct for side effects like logging.
Examine the effect below. Why does it cause an infinite loop?
import { createEffect, ofType, Actions } from '@ngrx/effects'; import { Injectable } from '@angular/core'; import { map } from 'rxjs/operators'; import * as MyActions from './actions'; @Injectable() export class MyEffects { loopEffect$ = createEffect(() => this.actions$.pipe( ofType(MyActions.loadData), map(() => MyActions.loadData()) )); constructor(private actions$: Actions) {} }
Think about what happens when an effect dispatches the same action it listens for.
The effect listens for 'loadData' and dispatches 'loadData' again, causing an endless cycle of the same action triggering the effect repeatedly.
Given the reducer and effect below, what will be the state after dispatching 'loadData'?
import { createReducer, on } from '@ngrx/store'; import * as MyActions from './actions'; export interface State { data: number[]; loading: boolean; } export const initialState: State = { data: [], loading: false }; export const myReducer = createReducer( initialState, on(MyActions.loadData, state => ({ ...state, loading: true })), on(MyActions.loadDataSuccess, (state, { data }) => ({ ...state, data, loading: false })) ); // Effect import { createEffect, ofType, Actions } from '@ngrx/effects'; import { Injectable } from '@angular/core'; import { map, delay } from 'rxjs/operators'; @Injectable() export class MyEffects { loadData$ = createEffect(() => this.actions$.pipe( ofType(MyActions.loadData), delay(1000), map(() => MyActions.loadDataSuccess({ data: [10, 20, 30] })) )); constructor(private actions$: Actions) {} }
Consider the timing of the effect and reducer updates.
Initially, 'loadData' sets loading to true. After 1 second, the effect dispatches 'loadDataSuccess' which updates data and sets loading to false.
In Angular with NgRx, why is it better to handle side effects like HTTP calls inside effects rather than inside components?
Think about separation of concerns and testability.
Effects help keep components focused on UI, centralize side effects, and improve maintainability and testing.