Skip to main content

Command Palette

Search for a command to run...

Mastering useEffect: A React Developer's Essential Hook

Published
•4 min read•View as Markdown

What is useEffect?

useEffect is a React hook that lets you perform side effects in functional components. Side effects can include things like:

  • Data fetching (e.g., from an API)

  • Subscribing to external services (e.g., WebSocket or events)

  • Manipulating the DOM directly

  • Starting/stopping timers

useEffect helps us manage these tasks, especially those that need to be done after a component has been rendered or in response to changes in state/props.

Basic Syntax of useEffect:

useEffect(() => {
  // Your side effect code here (e.g., data fetch, subscriptions, etc.)

  // Optional cleanup function to run when component unmounts or before re-running effect
  return () => {
    // Clean up side effects (e.g., clearInterval, unsubscribe, etc.)
  };
}, [dependencies]); // Dependencies array
  • Callback Function: The first argument is the function (effect) you want to run. This is your "side effect" code.

  • Dependencies Array: The second argument is an array of dependencies. It tells React when to run (or re-run) the effect.

    When Does useEffect Run?

    The timing of when useEffect runs depends on the dependencies array ([]) passed as the second argument:

    1. No Dependencies Array (useEffect(() => {...})):

      • useEffect will run after every render (on every component update).

      • This is generally inefficient unless you specifically need the effect to run on every render.

      • Example:

          useEffect(() => {
            console.log('This runs after every render');
          });
        
    2. Empty Dependencies Array (useEffect(() => {...}, [])):

      • If you pass an empty array ([]), useEffect will run only once—after the initial render (when the component mounts).

      • This mimics the behavior of componentDidMount in class components.

      • Example:

          useEffect(() => {
            console.log('This runs only once, on mount');
          }, []); // No dependencies, runs only once
        
    3. With Dependencies (useEffect(() => {...}, [dep1, dep2])):

      • If you pass an array of dependencies, useEffect will run once initially (on mount) and whenever one or more dependencies change.

      • Example:

          useEffect(() => {
            console.log('This runs when "prop" or "state" changes');
          }, [prop, state]); // Runs when "prop" or "state" changes
        
    4. Cleanup Function:

      • Inside useEffect, you can optionally return a cleanup function. This function will be called:

        • When the component unmounts (to avoid memory leaks).

        • Just before the effect is re-run, in case dependencies change.

      • Example:

          useEffect(() => {
            const timerId = setInterval(() => {
              console.log('Timer is running');
            }, 1000);
        
            // Cleanup function to clear the interval
            return () => {
              clearInterval(timerId); // Runs when component unmounts
            };
          }, []); // Runs only once
        

Common Use Cases for useEffect:

  1. Fetching Data from APIs:

    • You often want to fetch data from a server after the component mounts. To do this, you would use useEffect with an empty dependencies array so it runs only once.

    • Example:

        useEffect(() => {
          async function fetchData() {
            const response = await fetch('https://api.example.com/data');
            const data = await response.json();
            setData(data); // Assume setData updates your state
          }
      
          fetchData(); // Call the async function
        }, []); // Run once after the initial render
      
  2. Listening for Events (e.g., resizing window, mouse movement):

    • You might want to listen to events, like window resizing, and perform an action. Here, you also want to clean up the event listener when the component unmounts.

    • Example:

        useEffect(() => {
          const handleResize = () => {
            console.log('Window resized');
          };
      
          window.addEventListener('resize', handleResize);
      
          // Cleanup the event listener when the component unmounts
          return () => {
            window.removeEventListener('resize', handleResize);
          };
        }, []); // Add and remove event listener only once
      
  3. Setting up and Cleaning up Timers:

    • You can use useEffect to create and clean up timers. For example, starting a timer on mount and cleaning it up when the component unmounts.

    • Example:

        useEffect(() => {
          const timerId = setInterval(() => {
            console.log('Timer running');
          }, 1000);
      
          // Clean up the timer on unmount
          return () => {
            clearInterval(timerId);
          };
        }, []); // Only run once when component mounts
      
  4. Re-running Effects When Dependencies Change:

    • Sometimes, you want to run a side effect only when certain state or props change. In this case, you pass those variables as dependencies in the array.

    • Example:

        const [count, setCount] = useState(0);
      
        useEffect(() => {
          console.log('Count has changed:', count);
        }, [count]); // Effect runs only when "count" changes
      

Key Things to Remember:

  • Always provide a cleanup function if the effect sets up an ongoing process (like an interval, subscription, or event listener). Failure to clean up properly could lead to memory leaks or unwanted behavior.

  • Dependencies array:

    • If left out, useEffect will run after every render.

    • If it's empty ([]), it runs only once after the initial render (on mount).

    • If it contains values, it will run whenever those values change.

  • Side effects and reactivity: useEffect ensures that side effects are kept in sync with the component’s render cycle, reducing errors and helping manage resources efficiently.

More from this blog

Asawer

19 posts

FullStack Developer