SyntaxStudy
Sign Up
React Introduction to useEffect
React Beginner 1 min read

Introduction to useEffect

The useEffect hook lets you synchronise a component with an external system — the DOM, a network request, a timer, or any side effect that does not belong in the render phase. React runs the effect after every completed render by default, giving you a safe window to interact with the browser or kick off asynchronous work without blocking the paint. The dependency array is the key to controlling when an effect re-runs. Passing an empty array makes the effect run only once after the initial mount, which is the right choice for one-time setup such as fetching seed data or subscribing to an external store. Omitting the array entirely means the effect fires after every render, which is rarely what you want and can trigger infinite loops if the effect itself triggers a state update. When your effect allocates a resource — a subscription, a timer, an event listener — you must return a cleanup function. React calls the cleanup before re-running the effect and again when the component unmounts, preventing memory leaks and stale callbacks.
Example
import { useState, useEffect } from 'react';

function DataFetcher({ userId }) {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        // Reset state when userId changes
        setLoading(true);
        setError(null);

        let cancelled = false; // cancellation flag

        async function fetchUser() {
            try {
                const res = await fetch(`/api/users/${userId}`);
                if (!res.ok) throw new Error('Failed to fetch');
                const data = await res.json();
                if (!cancelled) {
                    setUser(data);
                    setLoading(false);
                }
            } catch (err) {
                if (!cancelled) {
                    setError(err.message);
                    setLoading(false);
                }
            }
        }

        fetchUser();

        // Cleanup: cancel stale request
        return () => { cancelled = true; };
    }, [userId]); // re-run whenever userId changes

    if (loading) return <p>Loading…</p>;
    if (error)   return <p>Error: {error}</p>;
    return <p>Hello, {user?.name}</p>;
}