useEffect Hook

Loading

The useEffect hook is one of the most powerful and widely used hooks in React. It allows you to handle side effects in your functional components, such as data fetching, subscriptions, manual DOM manipulation, and more. Before hooks were introduced, handling side effects was only possible in class components using lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount. With the useEffect hook, you can handle all of these behaviors in functional components.

1. What is the useEffect Hook?

The useEffect hook is used to perform side effects in functional components. Side effects are operations that can affect other components or interact with the outside world, such as:

  • Fetching data from an API
  • Subscribing to a service
  • Updating the DOM directly
  • Setting up event listeners
  • Cleaning up resources when the component unmounts

The useEffect hook runs after the component renders, and it runs by default after every render.

2. Syntax of useEffect Hook

useEffect(() => {
  // Your side effect logic here
}, [dependencies]);
  • The first argument is a callback function that contains the side effect logic.
  • The second argument is an optional dependency array that tells React when to re-run the effect (i.e., if the dependencies change). If no dependencies are passed, the effect runs after every render. If the array is empty, the effect runs only once when the component mounts.

3. Basic Example of useEffect Hook

Let’s look at a basic example where we fetch data from an API using useEffect and display it in a component:

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

function FetchData() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      });
  }, []); // Empty dependency array, so this runs only once when the component mounts

  return (
    <div>
      {loading ? <p>Loading...</p> : <pre>{JSON.stringify(data, null, 2)}</pre>}
    </div>
  );
}

export default FetchData;

In this example:

  • The useEffect hook fetches data from an API when the component mounts.
  • The empty dependency array ([]) ensures that the effect runs only once when the component is mounted (similar to componentDidMount in class components).

4. Dependencies Array in useEffect

The second argument of useEffect is an optional array of dependencies that allows you to control when the effect should re-run. The effect will only re-run if one of the dependencies has changed since the last render.

Example with Dependencies:

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

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

  useEffect(() => {
    const timer = setInterval(() => {
      setSeconds(prevSeconds => prevSeconds + 1);
    }, 1000);

    // Cleanup the timer when the component unmounts
    return () => clearInterval(timer);
  }, []); // Empty array ensures this runs once when the component mounts

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

export default Timer;

In this example:

  • The effect sets up a timer that updates the seconds state every second.
  • The cleanup function clearInterval is returned to stop the timer when the component unmounts, preventing memory leaks.

Example with Dependencies:

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

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

  useEffect(() => {
    if (count > 5) {
      setMessage('Count is greater than 5');
    } else {
      setMessage('');
    }
  }, [count]); // Effect runs every time `count` changes

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

export default Counter;

In this example:

  • The effect is dependent on count, so it will only run when count changes.

5. Cleaning Up Effects

If your side effect involves something that needs to be cleaned up (like subscriptions, timers, or manual DOM manipulation), you can return a cleanup function inside your useEffect callback. This cleanup function is called when the component is unmounted or before the effect runs again (if the dependencies have changed).

Example with Cleanup:

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

function Component() {
  const [status, setStatus] = useState('offline');

  useEffect(() => {
    // Simulate a subscription or event listener
    const interval = setInterval(() => {
      console.log('Checking online status...');
    }, 1000);

    // Cleanup function to clear the interval
    return () => {
      clearInterval(interval);
    };
  }, []); // Empty array ensures this effect runs only once when the component mounts

  return <p>Status: {status}</p>;
}

export default Component;

In this example:

  • The effect sets up an interval, but when the component unmounts, the cleanup function clears the interval, preventing a potential memory leak.

6. Running Effects on Mount and Unmount

You can simulate behaviors similar to componentDidMount and componentWillUnmount using useEffect.

  • To run an effect only once when the component mounts, pass an empty dependency array []: useEffect(() => { console.log('Component mounted'); }, []);
  • To simulate componentWillUnmount, return a cleanup function that will be called when the component unmounts: useEffect(() => { return () => { console.log('Component unmounted'); }; }, []);

Leave a Reply

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