17 Feb 2024




Intermediate

The useEffect hook in React.js is a function that allows you to perform side effects in functional components. Side effects can include data fetching, subscriptions, or any action that needs to be taken after the component is rendered. It helps manage the lifecycle of the component by executing code after rendering and optionally cleaning up resources when the component unmounts or when specific dependencies change.

Syntax of the useEffect hook:

import React, { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // Side effect code here
    // This code will run after every render
    // It can perform data fetching, subscriptions, or DOM manipulations

    // Return a cleanup function if necessary
    return () => {
      // Cleanup code here
      // This code runs when the component unmounts or before the effect runs again
    };
  }, [ dependencyArray ]); // Dependency array
  // Pass dependencies to the array to control when the effect runs
  // An empty array [] means the effect runs only once after the initial render

  return (
    // JSX code for rendering component
  );
}

Here's what happens with the useEffect hook:

  • Declaration: You declare the useEffect hook inside your functional component.

  • Side Effects: The function provided to useEffect is the side effect itself. It runs after every render by default, including the initial render.

  • Cleanup: You can return a cleanup function from the effect. This function runs before the component is removed from the UI or before the effect runs again. It's useful for cleaning up resources like subscriptions or event listeners to prevent memory leaks.

  • Dependency Array: You can also provide a dependency array as the second argument to useEffect. React will re-run the effect only if the values in the dependency array change between renders. If the array is empty, the effect runs only once after the initial render.

Key points of useEffect in React js :

  • Side Effects on Mounting:

    • useEffect is often used to perform side effects after the component has mounted.
    • Example:
      useEffect(() => {
        // Perform side effect on mount
        console.log('Component mounted');
      }, []);
      
  • Dependency Array:

    • You can specify dependencies in the second argument of useEffect. The effect will re-run if any of the dependencies change.
    • Example:
      useEffect(() => {
        // Perform side effect when count changes
        console.log('Count updated:', count);
      }, [count]);
      
  • Cleanup Function:

    • useEffect can return a cleanup function to perform cleanup operations before the component is unmounted or before the effect runs again.
    • Example:
      useEffect(() => {
        // Perform side effect on mount
        console.log('Component mounted');
      
        // Cleanup function
        return () => {
          console.log('Component will unmount');
        };
      }, []);
      
  • Conditional Effects:

    • You can conditionally apply effects based on some conditions within the effect or by changing dependencies.
    • Example:
      useEffect(() => {
        if (condition) {
          // Perform side effect based on condition
          console.log('Effect triggered');
        }
      }, [condition]);
      
  • Combining Multiple Effects:

    • You can use multiple useEffect hooks in a component to separate concerns and manage different side effects independently.
    • Example:
      useEffect(() => {
        // Effect 1
        console.log('Effect 1');
        
        return () => {
          // Cleanup for Effect 1
          console.log('Cleanup for Effect 1');
        };
      }, [dependency1]);
      
      useEffect(() => {
        // Effect 2
        console.log('Effect 2');
        
        return () => {
          // Cleanup for Effect 2
          console.log('Cleanup for Effect 2');
        };
      }, [dependency2]);
      
  • Asynchronous Effects:

    • You can use asynchronous functions inside useEffect. Just ensure that the function is defined inside the effect or is a separate function that is invoked within the effect.
    • Example:
      useEffect(() => {
        const fetchData = async () => {
          const data = await fetchDataFromAPI();
          console.log('Data fetched:', data);
        };
      
        fetchData();
      }, []);
      
  • Effect Dependencies and Closures:

    • Be careful with closures inside useEffect when using dependencies. The variables captured in closures may not have the latest values.
    • Example:
      useEffect(() => {
        const intervalId = setInterval(() => {
          // This callback captures the initial value of count
          console.log('Count:', count);
        }, 1000);
      
        return () => {
          clearInterval(intervalId);
        };
      }, [count]);
      
  • Skipping Effects on Mount:

    • You can use a ref to skip the execution of an effect on the initial mount.

    • Example:

      import React, { useEffect, useRef, useState } from 'react';
      
         function ExampleComponent() {
           const [count, setCount] = useState(0);
           const skipEffect = useRef(true);
      
           useEffect(() => {
         	// This effect will not run on mount
         	if (skipEffect.current) {
         	  skipEffect.current = false;
         	  return;
         	}
      
         	// Perform side effect
         	console.log('Effect triggered');
           }, [count]); // This effect depends on the count state
      
           return (
         	<div>
         	  <p>Count: {count}</p>
         	  <button onClick={() => setCount(count + 1)}>Increment</button>
         	</div>
           );
         }
      
         export default ExampleComponent;
      
  • Debugging Effects:

    • Use the console.log statements within useEffect to debug and understand the order of execution and dependencies.
    • Example:
      useEffect(() => {
        console.log('Effect running');
      
        return () => {
          console.log('Cleanup');
        };
      }, [dependency]);
      
  • Effect Dependencies Best Practices:

    • Be mindful of the dependencies you include in the dependency array. Omitting dependencies can lead to stale closures, and including unnecessary dependencies can lead to excessive re-renders.
    • Example:
      useEffect(() => {
        // Effect logic
      
        return () => {
          // Cleanup logic
        };
      }, [dependency1, dependency2]);
      
  • Dynamic Effects based on Props:

    • You can use props to dynamically influence the effects.
    • Example:
      useEffect(() => {
        // Effect logic based on props
      
        return () => {
          // Cleanup logic
        };
      }, [props.someProp]);
      
reactjs
usestate
hook