useEffect: Easy Guide with use-cases and examples

Dead Simple Chat Team

useEffect is a react hook that lets you sync react code/ application with an external system that does not use react such as an API

If you are looking for a React Native Chat SDK to build in app chat messaging application, you can consider DeadSimpleChat React Native SDK

How to use useEffect?

You need to call useEffect at the top of the component where you are using it because it is a React Hook (Hooks are just JS functions)

Basic Syntax

useEffect(() => {
  // the logic of the side effects
}, [dependencies-array]);

A Simple Example:

import { useEffect } from 'react';
import { createConnection } from './chatApp.js';

function Chat({ chatRoomId }) {
  const [serverUrl, setServerUrl] = useState('http://localhost:3000');

  useEffect(() => {
    const connection = createConnection(serverUrl, chatRoomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [serverUrl, roomId]);
  // ...
}
useEffect

Parameters

the setup function: The setup function contains the logic for the side effects. This setup function can also optionally return another function that is the clean up function

When the component is added to the DOM. First the React will run the setup function then after every re-render when the dependencies have changed the react will run the clean-up function and then the setup function

Dependencies Array Optional : The list of values

Dependency array is the second argument in the useEffect hook. It contains all the reactive values that are refrenced in the setup code

Reactive values are:

  • Props: Values that are passed down from the parent component
  • State: local storage for the component
  • Other Values:  Various functions or variables that are declared within the component body

The effect will run every time the reactive values that are in the dependency array changes. React does a shallow check with Object.is and if there is a change react re-runs the effects

Empty Array : Means that there are no dependencies and the effect will only run once when the compnent is rendered for the first time

No Array : If you do not include the array then the effect will run at every re-render of the component

Returns

The useEffect returns null

Caveats

Placement of the useEffect

  1. Only at the Top Level : You need to invoke the useEffect hook only at the top level because it is a react hook
  2. Conditional logic: You can't call useEffect inside loops of conditionals. If you need to do this extract a new component and move the state into it

Purpose of useEffect

  1. Only for syncing with an external system: If you not trying to sync with an external system then you probably do not need the useEffect Hook. External system means an API or any other code that is not react
  2. If you are not dealing with side effects, you probably do not need to use useEffect

Strict Mode Consideration

  1. Inside the Development mode : When you are running the useEffect in development mode the setup and cleanup functions will run an extra time before the first real run. This ensures that the code is reliable, that is the clean up is properly cleaning up the setup code

Dependency Caveats

Having functions and Objects as Dependencies

If you have Objects and functions that are defined in the component as dependencies in the useEffect hook. It could lead to unnecessary re-runs as Object or function notation creates new Objects and functions this could lead to useEffect running at every re-run

Solution

  • Remove ununessory functions or Objects.
  • Use other hooks like useCallback or useMemo to optimize the dependencies
  • Remove non-reactive logic out of the component or the useEffect Hook it the logic does not need to be there

Server Side Rendering

UseEffects can only run on the client side. Do not try running it on the server side.

Usage

How to connect to an external system using useEffect

In this example we are going to learn how to connect to an external system using the useEffect

Let us consider a component that needs to be connected to an external system.

For Example an network, like a browser API or a socket connection or a third party library

These systems are not controlled by react and hence are called as external

Step 1: Setting up

When the component is rendered for the first time, the function that we provided to the useEffect is executed

Here we will establish a connection to the external system

useEffect(() => {
   const serverConnection = createConnection(serverUrl, chatRoomId);
   connection.connect();
   // ...
}, [/* lsit of dependencies */]);
setting up

Step 2: Cleaning  Up

  • It is necessary to disconnect to external systems, when they are no longer needed. This is essential to prevent memeory leaks or unwanted side effects
  • The clean up is done by returning a function from useEffect caallback. The callback runs
  • 1. Before the component is removed from the UI and
  • 2. Before the useEffect reruns because of dependency changes.
useEffect(() => {
   //... setup function
   return () => {
      serverConnection.disconnect();
   };
}, [/* dependency array */]);
clean up function
Chat API Trusted by world’s biggest corporations | DeadSimpleChat
Chat API and SDk that supports 10 Million Concurrent Users. Features like Pre-Built turn key Chat Solution, Chat API’s, Customization, Moderation, Q&A, Language Translation.
DeadSimpleChat

step 3: Dependency Array

  • Dependency array contains reactive values (props, state, functions, variables inside components that should trigger a re-run of useEffect)
  • In the above example whenever the serverUrl or the chatRoomId changes the useEffect re runs

step 4: Lifecycle illustration

  • On Mount: establish the connection
  • On re-render : Whenever dependencies change re-render the use-effect and disconnect and reconnect with new values
  • On unMount : Disconnect from the external system

step 4: development mode

  • In development mode the react runs the cleanup function one extra time before running the useEffect code. This is to test whether the cleanup function is working properly or not
  • If this causes some problem in your application. This means that the clean up code is not working properly and not cleaning up after the Effect has taken place. You should fix the clean up code

step 5 : Best Practices

  1. Independent Operation: You should write every react effect as an independent from other effects. This ensures that no effect relies on other effects and the code is straightforward
  2. Setup/Cleanup Cycle Always write the clean up code keeping the setup code in mind, so as to properly unwind the setup after the effect has taken place.
Chat API Trusted by world’s biggest corporations | DeadSimpleChat
Chat API and SDk that supports 10 Million Concurrent Users. Features like Pre-Built turn key Chat Solution, Chat API’s, Customization, Moderation, Q&A, Language Translation.
DeadSimpleChat

Some Examples from basic to advanced

Example 1: News Feed

In this example we have a news feed component, that connects to an external system that is defined in the news.js file

The user clicks on the "Read News" button and the News Feed component is rendered on the page.

We are running the code in the development mode so there will be an additional  connect/disconnect cycle.

You can try and adjust the feedTopic and the serverUrl to observe the Effect connecting and disconnecting from the news feed

"Close News" will disconnect the Effect for the last time

App.js :

import "./styles.css";

import { useState, useEffect } from "react";
import { createSubscription } from "./news.js";

function NewsFeed({ feedTopic }) {
  const [serverUrl, setServerUrl] = useState("https://coolNewsWebsite.com");

  useEffect(() => {
    const subscription = createSubscription(serverUrl, feedTopic);
    subscription.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  }, [feedTopic, serverUrl]);

  return (
    <>
      <label>
        Server URL:{" "}
        <input
          value={serverUrl}
          onChange={(e) => setServerUrl(e.target.value)}
        />
      </label>
      <h1>Reading news on {feedTopic}!</h1>
    </>
  );
}

export default function App() {
  const [feedTopic, setFeedTopic] = useState("tech");
  const [show, setShow] = useState(false);
  return (
    <>
      <label>
        What news would you like to read:{" "}
        <select
          value={feedTopic}
          onChange={(e) => setFeedTopic(e.target.value)}
        >
          <option value="national">National</option>
          <option value="sports">Sports</option>
          <option value="world-affairs">World Affairs</option>
        </select>
      </label>
      <button onClick={() => setShow(!show)}>
        {show ? "Close News" : "Read News Feed"}
      </button>
      {show && <hr />}
      {show && <NewsFeed feedTopic={feedTopic} />}
    </>
  );
}
App.js

News.js:

export function createSubscription(serverUrl, feedTopic) {
  return {
    subscribe() {
      console.log(
        '✅ Subscribed to "' + feedTopic + '" news at ' + serverUrl + "..."
      );
    },
    unsubscribe() {
      console.log(
        '❌ Unsubscribed from "' + feedTopic + '" news at ' + serverUrl
      );
    }
  };
}
news.js

The newsFeed component subscribes to the news topics from 3 given choices. here is what is happening in the above example

  1. App Component The App component decides whether the news feed is visible or not and shows a selection of new topics available to the visitor
  2. useEffect : In the NewsFeed the useEffect hook manages the connection to the server. Whenever the feedTopic or the serverUrl changes the useEffect unsubcribes from the old topic and subscribes to the new topic
  3. Create Subscription In the file news.js the utility function connects to the news services. This is just a demo, in the real app here would be the logic of connecting and disconnecting from the news feed.
News website

Example 2: Tracking Screen Resizing

In this example we are going to track browser window resizing. This is a common use-case where use-effect can come in use.

Here we are going to listen to the resize event, using which you can keep track of the browser window's height and width.

import "./styles.css";

import { useState, useEffect } from "react";

export default function App() {
  const [dimensions, setDimensions] = useState({
    height: window.innerHeight,
    width: window.innerWidth
  });

  useEffect(() => {
    function handleResize(e) {
      setDimensions({ width: window.innerWidth, height: window.innerHeight });
    }
    window.addEventListener("resize", handleResize);
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return (
    <div style={{ padding: "20px" }}>
      <h1>The dimensions of the browser window</h1>

      <strong>Height: {dimensions.height}px</strong>
      <br />
      <strong>Width: {dimensions.width}px</strong>
    </div>
  );
}
App.js

Here we are showing how react can be used to listen to global browser events using the useEffect hook and then you can subsiquently take some action based on the dimensions of the browser window

Here is how this code is working

  1. Init: We are initializing the component's state with browser's windows current dimensions using the built in  window.innerHeight and  window.innerWidth functions
  2. useEffect The useEffect hook calls the handleResize function whenver the resize event triggers
  3. Cleanup : Inside the useEffect we have a clean up function that cleans up the event listener. This is done so as to avoid issues like memory leaks
  4. handleResize The function updates the state whenever the window dimension changes
  5. Render function The render function renders the UI on the screen
The Dimentions

Using useEffect in Custom Hooks

Effects are basically an escape hatch from the react ecosystem. They are basically a way to handle side-effects in functional components

If you have to write repeatable logic in different components when dealing with certain side-effects or external integrations like calling an API again and again in different components

This article is brought to you by DeadSimpleChat, Chat API and SDK for your website and apps

It is better to encapsulate the Effects code inside a Custom react Hook

It helps with code reuseability and makes the code more consise and readable

Custom Hooks allows you to abstract the Effects logic away from the component and focus on whatever the compnent needs to do.

Example 1: Fetching user data from an API

In this example we want to fetch user data from an API. Here many components want to fetch the data.

Instead of using useEffects in each of these components we are going to create an custom hook that would encapsulate the fetching logic and we will use that custom hook whenever we want to fetch the user data.

Creating the Custom Hook: useUserDetails

function useUserDetails(uniqueUserId) {
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    async function fetchUserData() {
      const response = await fetch(`/api/users/${uniqueUserId}`);
      const data = await response.json();
      setUserData(data);
    }

    fetchUserData();

    // Running Clean Up actions here

  }, [uniqueUserId]);

  return userData;
}
creating the custom Hook useUserDetails

the useUserDetails hook accepts a uniqueUserId and uses the useEffect to fetch the details about the user and returns the userData

Any component can use the useUserDetails hook to obtain details about the user without knowing how the details are being obtained

using the custom Hook : useUserDetails

function UserDetails({ uniqueUserId }) {
  const userData = useUserDetails(uniqueUserId);

  if (!userData) return <div>User Details are laoding...</div>;

  return (
    <div>
      <h1>{userData.userName}</h1>
      <p>{userData.greeting}</p>
      // ... any other user data we might want to show
    </div>
  );
}
using the useUserDetails custom hook

Example 1: Creating a useLocalStorage Hook

In this example we have an app where we store users preferences in localstorage and access the preferences in various components.

Instead of writing the logic of reading and writing to localStorage we are going to extract away the logic in a custom localStorage Hook

Note: If you are interested in reading more about this read our guide JavaScript LocalStorage

App.js :

 import "./styles.css";

import { useLocalStorage } from "./useLocalStorage.js";

function UserSettings() {
  const [username, setUsername] = useLocalStorage("username", "");

  return (
    <>
      <label>
        Name:{" "}
        <input value={username} onChange={(e) => setUsername(e.target.value)} />
      </label>
      <h1>Hello, {username}!</h1>
    </>
  );
}

export default function App() {
  return (
    <>
      <h2>Settings:</h2>
      <UserSettings />
    </>
  );
}

useLocalStorage.js

import { useState, useEffect } from "react";

export function useLocalStorage(key, initialValue) {
  // try to get the value from localStorage if unable use default value
  const localStorageValue = localStorage.getItem(key);
  const valueToUse = localStorageValue ? JSON.parse(localStorageValue) : initialValue;

  const [value, setValue] = useState(valueToUse);

  useEffect(() => {
    // save to localstorage the value changes
    localStorage.setItem(key, JSON.stringify(value));
  }, [value, key]);

  return [value, setValue];
}

  1. We are sync localStorage with state using the useLocalStorage hook
  2. The useLocalStorage hook tries to get the value from the localStorage and when it is unable to find the value it uses the default value
  3. we are using the useState hook inside the useLocalStorage to save the value in localStorage whenever the value changes
  4. The usLocalStorage returns a setter function to both display the value and update the stored value at the same time

Controlling a widget that is not built with react

Many times you need to connect with code that is not built with react. Maybe it is built with some other library like JQuery etc or something else

We will study an example where we control a widget which is not built with react using the useEffect hook

Example: Controlling an Audio widget with react useEffect

Let us consider a Audio widget, which is not built with react and we need to integrate it with the react code

App.js

Specifying Reactive dependencies

In useEffect you cannot choose your dependencies. Every reactive value must be stated as a dependency

The useEffect dependency list is determined by the surrounding code

let us look at an example to understand this better

function UserProfile({ uniqueUserId }) { // `uniqueUserId is a prop and hense a reactive value
  const [apiEndpoint, setApiEndpoint] = useState('https://testwebsite.com/user/uniqueuserid'); // the api endpoint is a reactive value, because it is stated as a state var

  useEffect(() => {
    const fetchUserData = async () => {
      const response = await fetch(`${apiEndpoint}/${uniqueUserId}`);
      const data = await response.json();
      // Component can do anything with the user data
    };
    
    fetchUserData();

    // No clean up is required because we are fetching data. But if you want a clean up function you can specify it here
      
  }, [apiEndpoint, uniqueUserId]); // The api endpoint and the uniqueUserId must be specified as dependencies in the useEffect
    // ...
}
examples

All reactive values must be specified as dependencies, here uniqueUserId and the apiEndpoint are reactive values and hense must be specified as dependencies.

Props and variables and functions declared inside of your component are reactive values

The reactive value changes will cause the component to re render.

function HelloUser({ userName }) { // `userName is a prop and hence a reactive value
  const [prefix, setPrefix] = useState('Hello User'); // the prefix is state and hense a reactive value

  useEffect(() => {
    document.title = `${prefix}, ${userName}!`; 

  }, [userName, prefix]); // useEffect needs to have both the dependencies mentioned in the dependency array
  // ...
}

userName is a prop hence it is a dependency

prefix is a state and hence it is also a dependency

So, both of these are mentioned in the dependency array

Thus explaining that all the reactive values must be mentioned in the dependency array

You might be interested in some of our other articles

Conclusion

In this article we have learned about React useEffect using use-cases and examples

I hope you liked the article and thanks for reading