Handling Side Effects & Working with the useEffect() HookEntry 1 of 7
What Side Effects Are
A side effect is any code that reaches outside the component's job of turning props and state into JSX.
Notes
A component function should be pure: the same props and state always produce the same JSX, and rendering changes nothing outside. Side effects break that rule, so they don't belong in the component body. Examples:
- Fetching data or reading the user's location.
- Reading or writing
localStorage. - Setting timers or intervals.
- Subscribing to events, sockets, or other external sources.
- Calling DOM methods such as
showModal()orfocus().
A side effect in the component body runs on every render. If it also updates state, it triggers another render, which runs it again: an infinite loop.
What / Why / When
- What
Work that affects or depends on something outside React's rendering.
- Why it matters
Rendering must stay predictable; React may render a component many times.
- When to care
Any time the code talks to the browser, the network, or a timer.
- Use case
Sorting a list of places by distance from the user's current location.
Code compare
import { useEffect, useState } from "react";type Place = { id: string; title: string; lat: number; lon: number };export function App() { const [availablePlaces, setAvailablePlaces] = useState<Place[]>([]); // ❌ In the body: runs every render, sets state, re-renders → infinite loop // navigator.geolocation.getCurrentPosition((pos) => setAvailablePlaces(...)); // ✅ In an effect: runs after the first render only useEffect(() => { navigator.geolocation.getCurrentPosition((position) => { const sorted = sortPlacesByDistance( AVAILABLE_PLACES, position.coords.latitude, position.coords.longitude, ); setAvailablePlaces(sorted); }); }, []); return <PlacesList places={availablePlaces} />;}A class component is instantiated once, so one-time setup goes in ngOnInit (or the constructor):
import { Component, OnInit, signal } from "@angular/core";@Component({ selector: "app-root", template: `<app-places-list [places]="availablePlaces()" />`,})export class AppComponent implements OnInit { availablePlaces = signal<Place[]>([]); ngOnInit() { navigator.geolocation.getCurrentPosition((position) => { this.availablePlaces.set( sortPlacesByDistance(AVAILABLE_PLACES, position.coords.latitude, position.coords.longitude), ); }); }}Differences and gotchas
- React re-runs the component function on every render, so it needs
useEffectto control when side effects run. Angular's class runs once, so lifecycle hooks are enough for one-time setup. - Avoid side effects in Angular template expressions for the same reason: they run on every change detection pass.
Quick reference
| React | Angular |
|---|---|
Side effect in useEffect | ngOnInit / constructor / effect() |
| Component body must stay pure | Template expressions must stay pure |