Bird
Raised Fist0
Angularframework~10 mins

Effect for side effects in Angular - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Effect for side effects
Component initializes
Effect declared with side effect logic
Effect runs after component setup
Side effect executes (e.g., logging, fetching)
Effect cleanup runs on component destroy or dependencies change
Component updates or unmounts
This flow shows how Angular runs an effect to perform side effects after component setup, then cleans up when needed.
Execution Sample
Angular
import { Component, effect, signal } from '@angular/core';

@Component({
  selector: 'app-counter',
  standalone: true,
  template: `<button (click)="count.set(count() + 1)">Increment</button>`
})
export class CounterComponent {
  count = signal(0);
  constructor() {
    effect(() => {
      console.log(`Count is: ${this.count()}`);
    });
  }
}
This Angular component uses an effect to log the count value whenever it changes.
Execution Table
StepTriggerState BeforeActionState AfterSide Effect Output
1Component initializescount=0Effect runs first timecount=0Console logs: 'Count is: 0'
2User clicks buttoncount=0count updated to 1count=1Console logs: 'Count is: 1'
3User clicks buttoncount=1count updated to 2count=2Console logs: 'Count is: 2'
4Component destroyedcount=2Effect cleanup runs (if any)count=2No console output
5No further updatescount=2No effect triggeredcount=2No console output
💡 Effect stops running after component is destroyed or no state changes occur.
Variable Tracker
VariableStartAfter 1After 2After 3Final
count01222
Key Moments - 3 Insights
Why does the effect run immediately when the component initializes?
The effect runs once right after declaration to capture the initial state and perform the side effect, as shown in step 1 of the execution_table.
Does the effect run if the signal value does not change?
No, the effect only runs when the signal value changes. Step 5 shows no effect triggered because count stays the same.
What happens to the effect when the component is destroyed?
The effect cleanup runs to release resources or cancel subscriptions, preventing memory leaks, as shown in step 4.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the value of count after step 2?
A2
B1
C0
DUndefined
💡 Hint
Check the 'State After' column in row for step 2.
At which step does the effect cleanup run?
AStep 5
BStep 3
CStep 4
DStep 1
💡 Hint
Look for 'Effect cleanup runs' in the 'Action' column.
If the user never clicks the button, how many times does the effect run?
AOnce
BTwice
CNever
DThree times
💡 Hint
Refer to step 1 and step 5 in the execution_table.
Concept Snapshot
Effect for side effects in Angular:
- Use effect() to run code reacting to signal changes.
- Runs immediately once after declaration.
- Runs again only when dependencies change.
- Cleanup runs on component destroy or dependency change.
- Ideal for logging, fetching, or subscriptions.
Full Transcript
In Angular, an effect runs side effect code after component setup and whenever its dependencies change. Initially, the effect runs once to capture the starting state. When a signal changes, the effect runs again to perform the side effect, such as logging. When the component is destroyed, the effect cleanup runs to free resources. This ensures side effects stay in sync with state and avoid leaks.

Practice

(1/5)
1. What is the main purpose of an Effect in Angular?
easy
A. To style components with CSS dynamically
B. To define the main UI layout of a component
C. To handle user input events directly in the template
D. To run side tasks like data loading or logging when app state changes

Solution

  1. 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.
  2. Step 2: Identify the role of Effects

    Effects run these side tasks automatically when app state changes, keeping main logic clean.
  3. Final Answer:

    To run side tasks like data loading or logging when app state changes -> Option D
  4. Quick 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
A. createEffect(() => this.actions$.subscribe(action => console.log(action)))
B. createEffect(() => this.actions$.map(action => action.type))
C. createEffect(() => this.actions$.pipe(ofType(loadData), tap(() => console.log('Loading'))))
D. createEffect(() => this.actions$.filter(action => action.type === 'loadData'))

Solution

  1. Step 1: Recall the correct RxJS operators for Effects

    Effects use pipe with operators like ofType to filter actions and tap for side effects.
  2. Step 2: Check each option's syntax

    createEffect(() => this.actions$.pipe(ofType(loadData), tap(() => console.log('Loading')))) correctly uses pipe, ofType, and tap. Others misuse operators or subscribe directly, which is incorrect inside Effects.
  3. Final Answer:

    createEffect(() => this.actions$.pipe(ofType(loadData), tap(() => console.log('Loading')))) -> Option C
  4. Quick 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:
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
A. The message 'Data loading started' is logged, and no new action is dispatched
B. The message is logged and a new action is dispatched automatically
C. Nothing happens because dispatch is false
D. An error occurs because tap cannot be used here

Solution

  1. Step 1: Understand the effect's dispatch option

    Setting dispatch: false means this Effect does not send out new actions after running.
  2. Step 2: Analyze the tap operator

    The tap operator runs side code like logging but does not change or dispatch actions.
  3. Final Answer:

    The message 'Data loading started' is logged, and no new action is dispatched -> Option A
  4. Quick 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
A. Using map without returning an action causes an error
B. tap cannot be used after map
C. ofType should be replaced with filter
D. createEffect must not use arrow functions

Solution

  1. Step 1: Check the map operator usage

    map must return a new action object for dispatching, but this.api.save() likely returns a Promise or void, not an action.
  2. Step 2: Understand effect dispatch requirements

    Effects expect actions to be returned for dispatch unless dispatch: false is set, which is missing here.
  3. Final Answer:

    Using map without returning an action causes an error -> Option A
  4. Quick 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
A. login$ = createEffect(() => this.actions$.pipe( ofType('LOGIN'), tap(() => this.authService.login()), map(() => ({ type: 'LOGIN_SUCCESS' })) ));
B. 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' })) )) ));
C. login$ = createEffect(() => this.actions$.pipe( filter(action => action.type === 'LOGIN'), map(() => this.authService.login()), map(user => ({ type: 'LOGIN_SUCCESS', user })) ));
D. login$ = createEffect(() => this.actions$.pipe( ofType('LOGIN'), map(action => this.authService.login(action.credentials)), map(user => ({ type: 'LOGIN_SUCCESS', user })) ));

Solution

  1. Step 1: Identify async handling with switchMap

    Using switchMap allows calling the async login API and switching to its result stream.
  2. Step 2: Handle success and error properly

    Inside switchMap, map creates a success action, and catchError returns a failure action wrapped in of to keep the stream alive.
  3. 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 B
  4. Quick 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