Effects let your Angular app do extra work when something changes, like fetching data or saving info. They help keep your app organized by handling these side tasks outside your main code.
Effect for side effects in Angular
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
Angular
import { effect, inject } from '@angular/core'; import { SomeService } from './some.service'; const someEffect = effect(() => { const service = inject(SomeService); service.doSomething(); });
Use effect to run code that reacts to changes or triggers side tasks.
Use inject() inside effects to get services or dependencies.
Examples
Angular
import { effect, inject } from '@angular/core'; import { LoggerService } from './logger.service'; const logEffect = effect(() => { const logger = inject(LoggerService); logger.log('Effect ran'); });
Angular
import { effect, inject } from '@angular/core'; import { DataService } from './data.service'; const fetchEffect = effect(() => { const dataService = inject(DataService); dataService.loadData(); });
Sample Program
This Angular component has a button. When clicked, it sets a signal to true. The effect watches this signal and calls the data service to load data, printing a message to the console.
Angular
import { Component, effect, inject, signal, Injectable } from '@angular/core'; @Injectable() class DataService { loadData() { console.log('Loading data...'); } } @Component({ selector: 'app-root', standalone: true, providers: [DataService], template: `<button (click)="load()">Load Data</button>`, }) export class AppComponent { private dataService = inject(DataService); private loadSignal = signal(false); constructor() { effect(() => { if (this.loadSignal()) { this.dataService.loadData(); } }); } load() { this.loadSignal.set(true); } }
Important Notes
Effects run automatically when the signals or dependencies they watch change.
Keep side effects like API calls or logging inside effects to keep your components clean.
Summary
Effects help run extra code when something changes in your app.
Use effects for tasks like loading data or logging.
They keep side tasks separate from your main app logic.
Practice
1. What is the main purpose of an
Effect in Angular?easy
Solution
Step 1: Understand what side effects mean in Angular
Side effects are extra tasks like fetching data or logging that happen outside the main app logic.Step 2: Identify the role of Effects
Effects run these side tasks automatically when app state changes, keeping main logic clean.Final Answer:
To run side tasks like data loading or logging when app state changes -> Option DQuick Check:
Effect = side tasks on state change [OK]
Hint: Effects run extra tasks when app data changes [OK]
Common Mistakes:
- Thinking Effects handle UI layout
- Confusing Effects with event handlers
- Believing Effects style components
2. Which of the following is the correct way to create an Effect in Angular using RxJS operators?
easy
Solution
Step 1: Recall the correct RxJS operators for Effects
Effects usepipewith operators likeofTypeto filter actions andtapfor side effects.Step 2: Check each option's syntax
createEffect(() => this.actions$.pipe(ofType(loadData), tap(() => console.log('Loading')))) correctly usespipe,ofType, andtap. Others misuse operators or subscribe directly, which is incorrect inside Effects.Final Answer:
createEffect(() => this.actions$.pipe(ofType(loadData), tap(() => console.log('Loading')))) -> Option CQuick Check:
Effect uses pipe + ofType + tap [OK]
Hint: Use pipe with ofType and tap inside createEffect [OK]
Common Mistakes:
- Using subscribe inside createEffect
- Using map instead of tap for side effects
- Using filter without ofType
3. Given this Effect code snippet:
What will happen when the 'LOAD_DATA' action is dispatched?
loadData$ = createEffect(() => this.actions$.pipe(
ofType('LOAD_DATA'),
tap(() => console.log('Data loading started'))
), { dispatch: false });What will happen when the 'LOAD_DATA' action is dispatched?
medium
Solution
Step 1: Understand the effect's dispatch option
Settingdispatch: falsemeans this Effect does not send out new actions after running.Step 2: Analyze the tap operator
Thetapoperator runs side code like logging but does not change or dispatch actions.Final Answer:
The message 'Data loading started' is logged, and no new action is dispatched -> Option AQuick Check:
dispatch false means no new action, tap logs side effect [OK]
Hint: dispatch: false means no new action dispatched [OK]
Common Mistakes:
- Assuming tap dispatches actions
- Thinking dispatch: false disables effect
- Confusing tap with map or switchMap
4. Identify the error in this Effect code:
saveData$ = createEffect(() => this.actions$.pipe(
ofType('SAVE_DATA'),
map(() => this.api.save()),
tap(() => console.log('Save triggered'))
));medium
Solution
Step 1: Check the map operator usage
map must return a new action object for dispatching, butthis.api.save()likely returns a Promise or void, not an action.Step 2: Understand effect dispatch requirements
Effects expect actions to be returned for dispatch unlessdispatch: falseis set, which is missing here.Final Answer:
Using map without returning an action causes an error -> Option AQuick Check:
map must return action for dispatch [OK]
Hint: map must return an action unless dispatch: false [OK]
Common Mistakes:
- Ignoring missing action return in map
- Thinking tap cannot follow map
- Confusing ofType with filter
5. You want to create an Effect that listens for a 'LOGIN' action, calls an async login API, and then dispatches either 'LOGIN_SUCCESS' or 'LOGIN_FAILURE' based on the result. Which code snippet correctly implements this?
hard
Solution
Step 1: Identify async handling with switchMap
UsingswitchMapallows calling the async login API and switching to its result stream.Step 2: Handle success and error properly
Inside switchMap,mapcreates a success action, andcatchErrorreturns a failure action wrapped inofto keep the stream alive.Final Answer:
login$ = createEffect(() => this.actions$.pipe( ofType('LOGIN'), switchMap(action => this.authService.login(action.credentials).pipe( map(user => ({ type: 'LOGIN_SUCCESS', user })), catchError(() => of({ type: 'LOGIN_FAILURE' })) )) )); -> Option BQuick Check:
Use switchMap + map + catchError for async effects [OK]
Hint: Use switchMap with map and catchError for async API calls [OK]
Common Mistakes:
- Using tap instead of switchMap for async calls
- Not handling errors with catchError
- Returning promises instead of observables
