React Hooks: useEffect

React Hooks: useEffect

Welcome to the another article in the React Hooks series, where the magic of managing side effects unfolds! If React components are the building blocks of your web applications, then useEffect is the dynamic glue that connects them to the wider world.

In the ever-evolving landscape of web development, harnessing the power of side effects is essential for creating robust and interactive user interfaces. Imagine a world where your components seamlessly sync with external data sources, respond to user interactions, and gracefully handle the ebb and flow of the application lifecycle. This is precisely where useEffect steps into the spotlight.

Let's dive in and discover the captivating world of useEffect—where React components come to life. 🚀✨

Introduction

useEffect is a React Hook that lets you perform side effects in your components, such as data fetching, subscriptions, manual DOM manipulations, or any other operations that need to take place after the component has been rendered.

A useEffect hook takes in two arguments:

setup: this is a function that contains your useEffect's logic. This function is the side effect you want to perform. It runs after the component has been rendered. This can include data fetching, setting up subscriptions, or any code that needs to run after the component is displayed. You can also define an optional cleanup function in this logic that React will run after your component has been removed from the DOM. React will also first run the cleanup function with the old values before running the setup function with the new values when a re-render is triggered by changed dependencies.

dependency array (optional): an array of reactive values e.g. state, props, functions and variables declared inside your component that your setup function is dependent on to run. If any of the dependencies change between renders, the effect function will run again. If the dependencies array is empty, the effect will run only once after the initial render.

cleanup function (optional): If your effect has cleanup requirements (e.g., unsubscribing from a subscription), you can return a function from the useEffect. This function will be called before the component is unmounted, and also before the next effect run if the dependencies change.

useEffect(setup, dependencies)

Effects are typically used to “step out” of your React code and synchronize with some external system. This includes browser APIs, third-party widgets, network, and so on. Here are some situations where you might not need an Effect.

An example

In this example, the external system we would be trying to synchronize with is the browser API. We want to monitor an event, window resizing, in the global window object.

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

export default function ResizeListener() {
  // State to store the window dimensions
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  // useEffect to add event listener for window resize
  useEffect(() => {
    // Event handler function to update windowSize state
    const handleResize = () => {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    // Add event listener on component mount
    window.addEventListener("resize", handleResize);

    // Cleanup function to remove event listener on component unmount
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []); // Empty dependency array for running the effect only once after the initial render

  return (
    <div>
      <p>Window Width: {windowSize.width}</p>
      <p>Window Height: {windowSize.height}</p>
      {windowSize.width < 768 ? <p>Mobile</p> : <p>Desktop</p>}
    </div>
  );
}

In the component above, useEffect lets us connect to the window object and listen to its resize event. This effect lets us add an event listener to our window object when the component mounts, set the window size for display in our UI, and then remove our event listener in a cleanup function, after our component unmounts.

Usage

Here are some common use cases of the useEffect hook:

  1. Component Lifecycle Operations:

     useEffect(() => {
       // Code to run after each render
       return () => {
         // Code to run before the component is unmounted
       };
     }, [/* dependencies */]);
    
  2. Subscription Management:

     useEffect(() => {
       // Subscribe to a data stream or WebSocket
       const subscription = subscribeToData(data => {
         // Handle incoming data
         setData(data);
       });
       // Cleanup: Unsubscribe when component is unmounted
       return () => {
         subscription.unsubscribe();
       };
     }, [/* dependencies */]);
    
  3. DOM Manipulation:

     useEffect(() => {
       // Manipulate the DOM after component renders
       document.title = `New Title`;
       // Cleanup: Revert changes when component is unmounted
       return () => {
         document.title = `Original Title`;
       };
     }, [/* dependencies */]);
    
  4. Data Fetching:

     useEffect(() => {
       const fetchData = async () => {
         // Fetch data from an API
         const response = await fetch('https://api.example.com/data');
         const result = await response.json();
         // Update state with fetched data
         setData(result);
       };
       fetchData();
    
       // cleanup function would abort the network request if dependency changes or ignore its result
       // learn more https://developer.mozilla.org/en-US/docs/Web/API/AbortController
     }, [/* dependencies */]);
    
  5. Event Listeners:

     useEffect(() => {
       const handleClick = () => {
         // Handle click event
       };
       // Add event listener on mount
       document.addEventListener('click', handleClick);
       // Cleanup: Remove event listener on unmount
       return () => {
         document.removeEventListener('click', handleClick);
       };
     }, [/* dependencies */]);
    
  6. Interval or Timeout Operations:

     useEffect(() => {
       const intervalId = setInterval(() => {
         // Code to run at intervals
       }, 1000);
       // Cleanup: Clear interval on unmount
       return () => {
         clearInterval(intervalId);
       };
     }, [/* dependencies */]);
    
  7. Dependency-based Operations:

     useEffect(() => {
       // Code to run when dependencies change
     }, [dependency1, dependency2]);
    
  8. Document Title Updates:

     useEffect(() => {
       document.title = 'New Page Title';
     }, [/* dependencies */]);
    
  9. Animation Effects:

     useEffect(() => {
       // Trigger animations or transitions after render
       // or connect to a 3rd party animation library and start animation on mounted DOM node
    
       // Cleanup: stop animation on unmount
         return () => {
         };
     }, [/* dependencies */]);
    

Recap

useEffect provides a flexible way to handle side effects in React components. The key is to use it for operations that involve interactions with external systems, subscriptions, or anything that goes beyond the normal rendering of the component. I hope you learned something and now understand the useEffect hook and how to use it in your application.

Please leave a like if this was helpful. Comment also if you have questions.

Happy Coding🙌