Day 10: Understanding useEffect React Hook
4 mins read

Day 10: Understanding useEffect React Hook

In today’s React learning series, we will deep dive into useEffect React Hook. So far in this React series, we’ve learned how to manage state with useState, render lists, handle events, and more. But apps don’t just display data — they also need to fetch data, update the document title, listen to events, and clean up after themselves.

This is where useEffect comes in.


What is useEffect?

useEffect is a built-in React Hook that lets you perform side effects in functional components.

👉 But what’s a side effect?
A side effect is anything that affects something outside the component. Examples:

  • Fetching data from an API
  • Subscribing to an event (like key presses)
  • Updating the document title
  • Setting up timers (setTimeout, setInterval)

Before Hooks, these were only possible in class components using lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount). With useEffect, we can now do it directly in functional components.

Basic Syntax

useEffect(() => {
  // code that runs after render
});
  • The function inside useEffect runs after every render by default.
  • We can control when it runs using the dependency array (explained later).

Example 1: Updating Document Title

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

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

  useEffect(() => {
    document.title = `Count: ${count}`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click Me</button>
    </div>
  );
}

export default Counter;

👉 Every time count changes, React re-renders and the effect updates the document title.


Controlling When useEffect Runs

By default, useEffect runs after every render. But often, you don’t want that. That’s where the dependency array comes in.

Run Once (on Mount)

useEffect(() => {
  console.log("Component mounted!");
}, []);
  • An empty dependency array [] means the effect runs only once (when the component first renders).
  • Useful for things like API calls or subscriptions.

Run When Certain State Changes

useEffect(() => {
  console.log(`Count changed: ${count}`);
}, [count]);
  • Here, the effect runs only when count changes.
  • This improves performance by preventing unnecessary runs.

Cleanup with useEffect

Sometimes, side effects need to be cleaned up — for example, when removing event listeners or clearing timers.

Example: Timer with Cleanup

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

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(prev => prev + 1);
    }, 1000);

    // Cleanup function
    return () => clearInterval(interval);
  }, []);

  return <h2>Timer: {seconds} seconds</h2>;
}

export default Timer;

👉 Without cleanup, multiple intervals would run and cause bugs. Cleanup ensures we “unsubscribe” when the component unmounts.

Example: Fetching Data

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

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

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then(res => res.json())
      .then(data => setUsers(data));
  }, []); // run once on mount

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

export default Users;

👉 This is one of the most common use cases of useEffect — fetching data when a component loads.


Common Mistakes with useEffect

  • Missing dependencies: Always include variables you use inside useEffect in the dependency array.
useEffect(() => {
  console.log(count);
}, []); // ❌ count is missing from dependencies
  • Overusing useEffect
    Not everything needs useEffect. For example, simple calculations can be done directly in render.
  • Forgetting cleanup
    Not cleaning up event listeners or intervals can cause memory leaks.

Summary

  • useEffect lets you perform side effects in React functional components.
  • By default, it runs after every render.
  • Use the dependency array to control when it runs:
    • [] → run once (on mount).
    • [value] → run when value changes.
  • Always use cleanup when needed (timers, listeners).
  • Perfect for tasks like fetching data, updating the DOM, or handling subscriptions.

What’s Next?

Now that you know the basics of useEffect, in Day 11 we’ll explore useRef — a hook that helps us access DOM elements directly and persist values across renders without causing re-renders.

Leave a Reply

Your email address will not be published. Required fields are marked *