REACT useEffect

The useEffect hook in React lets you perform side effects in functional components, such as data fetching, setting up subscriptions, or manually updating the DOM. It is a powerful and essential tool to manage lifecycle events in React’s functional components.

Syntax

useEffect(() => {
    // Side effect code here

    return () => {
        // Cleanup code here (optional)
    };
}, [dependencies]);

Try It Now

  • First argument: A function that contains the side effect logic.
  • Second argument (dependencies): An array that determines when the effect runs. It controls re-execution based on state or prop changes.

When to Use useEffect

  1. Fetching data (e.g., API calls).
  2. Setting up subscriptions (e.g., WebSocket or event listeners).
  3. Updating the DOM (e.g., document title).
  4. Cleaning up resources (e.g., clearing timers or subscriptions).

Basic Example: Without Dependencies

The effect runs after every render.

import React, { useState, useEffect } from "react";

function Counter() {
    const [count, setCount] = useState(0);

    useEffect(() => {
        console.log(`Count updated: ${count}`);
    });

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
}

export default Counter;

Try It Now

Using Dependencies

The effect runs only when specific dependencies change.

useEffect(() => {
    // Code runs only when "count" changes
}, [count]);

Try It Now

Example:

import React, { useState, useEffect } from "react";

function Message() {
    const [message, setMessage] = useState("");

    useEffect(() => {
        console.log("Message changed:", message);
    }, [message]);

    return (
        <div>
            <input
                type="text"
                value={message}
                onChange={(e) => setMessage(e.target.value)}
            />
            <p>{message}</p>
        </div>
    );
}

export default Message;

Try It Now

Using useEffect for Data Fetching

import React, { useState, useEffect } from "react";

function UsersList() {
    const [users, setUsers] = useState([]);

    useEffect(() => {
        fetch("https://jsonplaceholder.typicode.com/users")
            .then((response) => response.json())
            .then((data) => setUsers(data));
    }, []); // Empty dependency array: Runs only once after the initial render.

    return (
        <ul>
            {users.map((user) => (
                <li key={user.id}>{user.name}</li>
            ))}
        </ul>
    );
}

export default UsersList;

Try It Now

Cleanup in useEffect

If the effect involves resources that need to be released (e.g., subscriptions or timers), use the cleanup function.

useEffect(() => {
    const timer = setInterval(() => {
        console.log("Timer running...");
    }, 1000);

    // Cleanup the timer when the component unmounts
    return () => {
        clearInterval(timer);
    };
}, []); // Empty dependency array ensures the cleanup is tied to unmount.

Try It Now

Multiple useEffect Hooks

You can use multiple useEffect hooks to separate concerns.

import React, { useState, useEffect } from "react";

function MultipleEffects() {
    const [count, setCount] = useState(0);
    const [message, setMessage] = useState("");

    useEffect(() => {
        console.log(`Count: ${count}`);
    }, [count]);

    useEffect(() => {
        console.log(`Message: ${message}`);
    }, [message]);

    return (
        <div>
            <button onClick={() => setCount(count + 1)}>Increment Count</button>
            <input
                type="text"
                value={message}
                onChange={(e) => setMessage(e.target.value)}
            />
        </div>
    );
}

export default MultipleEffects;

Try It Now

Common Scenarios

1. Run Effect Only Once

Add an empty dependency array ([]) to run the effect only after the first render.

useEffect(() => {
    console.log("Component mounted");
}, []); // Runs only once.

Try It Now

2. Run Effect on State/Prop Change

Specify the state/prop in the dependency array to trigger the effect when it changes.

useEffect(() => {
    console.log("Dependency changed");
}, [dependency]); // Runs whenever "dependency" changes.

Try It Now

3. Cleanup on Component Unmount

Return a cleanup function to handle unmount logic.

useEffect(() => {
    const interval = setInterval(() => {
        console.log("Running...");
    }, 1000);

    return () => {
        clearInterval(interval); // Cleanup when the component unmounts
    };
}, []);

Try It Now

Key Points to Remember

  1. Avoid unnecessary renders:
    • Use dependencies wisely to avoid infinite loops or redundant effects.
  2. Keep effects clean:
    • Perform only the necessary side effects inside useEffect.
  3. Handle asynchronous tasks properly:
    • Always manage cleanup when dealing with asynchronous calls (e.g., canceling fetch requests or timers).
  4. Separate concerns:
    • Use multiple useEffect hooks for different responsibilities instead of combining all logic in one.

Best Practices

  • Always specify dependencies explicitly.
  • Use cleanup functions to avoid memory leaks.
  • Avoid directly mutating states or props inside useEffect.

 

useEffect is an essential hook for managing side effects in React.