Quantum Tech Newz Logo
HomeWhat’s NewAIReactJS

Understanding useEffect() hooks: simplifying with its usecases

Last updated - 04 May, 2025, 10 minute reading

useEffect : — useEffect allows functional components to handle side effects. These tasks, called side effects, include things like making API requests, starting timers, or Setting up event listeners. You no longer need class-based lifecycle methods like componentDidMount, componentDidUpdate, or componentWillUnmount — you can handle all those within functional components now.

Here are some common scenarios for useEffect with examples:

1. Running after every render : Without a dependency array, useEffect runs each time the component updates. This is less common as it can easily lead to a performance or infinite rendering issue if not handled carefully.


import React, { useEffect } from 'react';

function MyComponent(){

 useEffect(()=>{
	//On every render cycle of the component, this console statement will run.
	console.log('component render or update');
 });

 return(
	<div>
		<p>Check useEffect console. </p>
	</div>
 );
}

2. Running effect after initial render (similar to componentDidMount) : By providing an empty dependency array like []. You instruct React to only run the effect when the page loads or mounts. This is commonly used for calling APIs and for page initial setup.


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

function DataFetcher() {

  const [data, setData] = useState(null);

  useEffect(() => {
	//It runs only one time, immediately after the initial render of the component.
	fetch('https://api.example.com/data')
      .then(data => setData(data));
  }, []); // Empty dependency array

  return (
    <div>
     {data ? (
        <p> Data loaded: {JSON.stringify(data)}</p>
      ) : (
        <p> Loading data...</p>
      )}
    </div>
  );
 }

3. Running after specified state or props changes : State and props can be included in the dependency array to make sure the effect runs when they change. useEffect is triggered again if any item listed in the dependency array gets updated. It’s a helpful way to ensure side effects respond only when specific pieces of data are updated.

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

function LiveFilter({ filterTerm }) {

  const [items, setItems] = useState([]);

  const [filteredItems, setFilteredItems] = useState([]);

  useEffect(() => {
    // Simulate fetching initial items
    const initialItems = [
      'Apple',
      'Banana',
      'Cherry',
      'Date',
      'Grape'
    ];
	
    setItems(initialItems);

  }, []); // Initialize the items only once when the component mounts

  useEffect(() => {

    // This effect filters items whenever filterTerm or items are updated

    const results = items.filter(item =>

      item.toLowerCase().includes(filterTerm.toLowerCase())

    );

    setFilteredItems(results);

  }, [filterTerm, items]); // The effect will run when either filterTerm or items change

  return (

    <div>

      <p>Filtering by: {filterTerm}</p>

      <ul>

        {filteredItems.map(item => (

          <li key={item}>{item}</li>

        ))}

      </ul>

    </div>

  );

}

4. Cleaning Up Side Effects : Some side effects, like setting up subscriptions, event listeners, or timers, require cleanup when the page unmounts because this might cause unexpected behavior or memory leaks. or when effects re-run. You can add a cleanup step inside useEffect by returning a function.


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

function Timer() {

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

  useEffect(() => {

    const intervalId = setInterval(() => {

      setCount(prevCount => prevCount + 1);

    }, 1000);

    // Cleanup function to clear the interval

    return () => {

      clearInterval(intervalId);

    };

  }, []); // Empty dependency array means this effect runs once on load and cleans up on removed

  return (

    <div>

      <p>Timer: {count}</p>

    </div>

  );

}

5. Interacting with the DOM : While React encourages declarative DOM manipulation through JSX and state. You might occasionally need to interact with DOM directly (e.g., measuring elements, focusing inputs).

useEffect is the right place to do this.

import React, { useEffect, useRef } from 'react';

function AutoFocusInput() {

  const inputRef = useRef(null);

  useEffect(() => {

    // After the component loads, the cursor is placed in the input box automatically.

    inputRef.current.focus();

  }, []); // Run once on mount

  return (

    <div>

      <input ref={inputRef} type="text" />

    </div>

  );

}

6. Data Fetching with Dependencies : Fetching data often depends on props or state. Including these dependencies in the array ensures that the data is re-fetched when the relevant values change.

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

function UserProfile({ userId }) {

  const [userData, setUserData] = useState(null);

  useEffect(() => {

    setUserData(null); // Clear previous data

    fetch(`https://api.example.com/users/${userId}`)

      .then(response => response.json())

      .then(data => setUserData(data));

  }, [userId]); // Re-run effect when userId changes

  return (

    <div>

      {userData ? (

        <div>

          <h2>{userData.name}</h2>

          <p>{userData.bio}</p>

        </div>

      ) : (

        <p>Loading user data...</p>

      )}

    </div>

  );

}

Understanding how the dependency array and cleanup function behave in each case helps you use useEffect properly for managing side effects in React. Remember to always include all values from your component scope that the effect depends on in the dependency array to avoid stale closures and ensure your effects run at the correct times.


Sudhir Yadav, Senior Software Engineer