40. useEffect

useEffect is a React hook that lets you perform side effects in functional components. Common use cases include:

  • Establishing a database connection when the DOM content loads.
  • Updating the page title when the content changes.

Note: The useEffect hook runs after the component has rendered.

41. What to Put in useEffect

Use useEffect for:

  • Network requests
  • Operations that take time to complete (e.g., fetching data, setting timers, etc.)

42. useEffect Syntax

42.1. Importing useEffect

import React, { useEffect } from 'react';

42.2. useEffect Syntax

useEffect(() => {
  // code here
  return () => {
    // cleanup code here
  };
}, [dependencies]);
  • The first argument is a function containing the code to execute.
  • The second argument is an array of dependencies. If any dependency changes, the function runs again.
  • The return statement is optional and is used for cleanup tasks, such as removing event listeners or canceling subscriptions. This cleanup function is executed:
    • Just before the the useEffect function runs again cause due to dependency change, with variables from the previous render.
    • After the component unmounts (i.e., when removed from the DOM).

Note: When your component is added to the DOM, React runs the setup function. After each re-render with changed dependencies, React first executes the cleanup function (if provided) with old values, then runs the setup function with new values.

Example:

useEffect(() => {
  const id = setTimeout(() => {
    console.log(count);
  }, 1000);

  return () => {
    clearTimeout(id);
  };
}, [count]);
  • In this example, the useEffect hook runs whenever the count variable changes. It sets a timeout to log the count value after 1 second, and the cleanup function clears the previous timeout before the next execution.

Cleanup Function:

  • Used for tasks like removing event listeners or clearing timeouts.
  • Ensures stale operations are cleared before new ones are executed.
  • Executes when dependencies change or when the component unmounts.

43. Variations of useEffect

43.1. useEffect Without Dependencies Array

useEffect(() => {
  // code here
});
  • The useEffect function runs after every re-render.

43.2. useEffect With Empty Dependencies Array

useEffect(() => {
  // code here
}, []);
  • The useEffect function runs only once after the initial render, making it ideal for tasks like loading local storage data.

43.3. useEffect With Multiple Dependencies

useEffect(() => {
  // code here
}, [count, name]);
  • The useEffect function runs when either count or name changes.

Note: In all of the variation, useEffect always runs after the first render no matter what is passed in the dependencies array.

Example: Loading Local Storage Data

Correct Usage:

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

const App = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    const data = localStorage.getItem('data');
    if (data) {
      setData(JSON.parse(data));
    }
  }, []);

  return (
    <div>
      {data.map((item, index) => (
        <p key={index}>{item}</p>
      ))}
    </div>
  );
};

Incorrect Usage:

import React, { useState } from 'react';

const App = () => {
  const [data, setData] = useState([]);

  const loadData = () => {
    const data = localStorage.getItem('data');
    if (data) {
      setData(JSON.parse(data));
    }
  };

  loadData();

  return (
    <div>
      {data.map((item, index) => (
        <p key={index}>{item}</p>
      ))}
    </div>
  );
};
  • Problem: Calling loadData directly causes an infinite loop because it triggers a re-render, which calls loadData again.
  • Solution: Use useEffect with an empty dependency array to ensure the function runs only once after the initial render.