React useEffect: A complete guide with examples

React useEffect is a powerful and essential hook that allows you to synchronize a component with an external system.

Using the react useEffect in functional components you can do things like fetching data, interacting with DOM elements and subscribing to event listeners.

Thus useEffect hook is an integral part of react development

useEffect(setup, dependencies?)

or

useEffect(()=>{
// some function 
},[/*dependencies array*/])

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat API and SDK.

How to use useEffect

Call the useEffect at the top of your component to declare an effect

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

function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:3000');

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

the useEffect function accepts two arguments:

  1. A function (also called as setup): that is the effect and

  2. An Array: An array containing dependencies

  • setup: Setup is the function with your effects logic. Your setup might additionally call a cleaner function.

When the component is first added to the DOM, the react runs the setup function.

React runs the setup function will run on every re-render, only if one of the dependencies has changed

When the setup function is run, react will first run the clean up funtion with old dependencies (if you provided the clean up function that is) and then run the setup function with new values

After the component is removed from the the DOM the react will run the clean up function for one last time.

  • Optional dependencies: All the reactive values that are mentioned inside of the setup code.

Reactive values include props, functions and all variables that are declared inside your component body.

The list of dependencies must be a constant number of items, they should not change and they should be written in line in an array like

[dep1, dep2 dep3]

Using the Object.is a notification the react compares each item with its previous value.

If you omit the dependencies array react will run the useEffect function after every re-render of the component.

This can lead to unintended consequences and performance issues. To make it so that the useEffect runs only once and if we don't

  • useEffect returns undefined

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat API and SDK.

Things to remember

  • useEffect is a hook, so you cannot call it inside loops or conditions. You can only call the useEffect at the top of your component

  • If you are not trying to synchronize with some external system like APIs, database, local storage etc then you don't need to use useEffect

  • When strict mode is on React will run one more the setup clean up cycle. If this causes a problem then you should implement a clean up function

  • Effects only run on the client side they don't run on the server

  • usually what happens is that the browser repaints the screen before process the state updates inside your effect

  • If you want to block the browser from repainting the screen you need replace useEffect with useLayoutEffect

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat API and SDK.

Some Salient Points

Connecting to an external system.

The systems like API, database, or third party libraries are displayed on the page. But these systems aren't controlled by react and hence are called external

If you want to connect your component to an external system, you can call useEffect at the top level of your component like so

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

function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:3000');

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

this is how the system works

The useEffect accepts two arguments

  1. A setup function with setup code (code that connects with the external resource) that connects to the system

1.a. The setup function returns a clean up function with clean up code that disconnects from the system

2. A list of dependencies including every value that the component inside the functions

React will call your setup and clean up functions multiple times whenever it is nessasory

These are the times your component might re-render

  • When the first time your setup code runs and your component is added to the page

  • Every time your dependencies have changed when your component re-renders

  • First, your clean-up code runs with the old dependencies

  • then your setup code runs with new props and state

  • your clean up code runs a final time when your component is removed from the page

Let us see what is happening with our example above

  1. When the chat Room component gets added to the pafge it will connect to the chat room with initial serverURl and roomId

2. If either the serverUrl or the roomId Changes because of the re-render. cause the user got to another chat room or the system connected the user to another server then the useEffect with a disconnect from the previous server or room and connect to the new room

3. When the chat room component is removed from the page the useEffect will disconnect the server and the chat room one last time

4. To help you debug your application react will run the setup and cleanup functions again before the setup

5. If this causes visible issues there is something wrong with your clean-up function. The clean-up function should stop or undo whatever the setup was doing

6. The rule of thumb is that the user should not be able to distinguish between the development where the set up clean up and setup is happening and in production where set up and clean up happens

Note: External system means any piece of code that is not controlled by react this could include

  • A timer that is controlled with setInterval() setTimeout() clearInterval() etc

  • An event subscription using window.eventListener() and window.removeEventListener()

  • third-party animation library with an API like animation.start() and animation.reset()

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat API and SDK.

Example 1 Connecting to a chat server

In this example, the ChatRoom component uses an Effect to stay connected to the external system. It uses roomId as an prop to identify a chat room. ServerUrl is the state variable.

Chat Room component has the useEffect hook to create a connection when the roomId or the serverURL changes

when the component is unmounted it disconnects from the server.

Lastly, the component renders an input field for the server URL and a welcome message

App.js

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

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

  return (
    <>
      <label>
        Server URL:{' '}
        <input
          value={serverUrl}
          onChange={e => setServerUrl(e.target.value)}
        />
      </label>
      <h1>This is the  {roomId} room!</h1>
    </>
  );
}

export default function App() {
  const [roomId, setRoomId] = useState('general');
  const [show, setShow] = useState(false);
  return (
    <>
      <label>
        Choose the chat room:{' '}
        <select
          value={roomId}
          onChange={e => setRoomId(e.target.value)}
        >
          <option value="cool">cool</option>
          <option value="awesome">awesome</option>
          <option value="movies">movies</option>
        </select>
      </label>
      <button onClick={() => setShow(!show)}>
        {show ? 'Close chat' : 'Open chat'}
      </button>
      {show && <hr />}
      {show && <ChatRoom roomId={roomId} />}
    </>
  );
}
export function createConnection(serverUrl, roomId) {
  // A real implementation would actually connect to the server
  return {
    connect() {
      console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...');
    },
    disconnect() {
      console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl);
    }
  };
}

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat API and SDK.

Example 2: Using useEffect to track browsers pointer movement

In this example, the external event is the browser's DOM. Normally you can have event listeners with the JSX. but you cannot listen to the global window object like this

An effect lets you connect to the window object and listen to the events

import { useState, useEffect } from 'react';

export default function App() {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    function handleMove(e) {
      setPosition({ x: e.clientX, y: e.clientY });
    }
    window.addEventListener('pointermove', handleMove);
    return () => {
      window.removeEventListener('pointermove', handleMove);
    };
  }, []);

  return (
    <div style={{
      position: 'absolute',
      backgroundColor: 'pink',
      borderRadius: '50%',
      opacity: 0.6,
      transform: `translate(${position.x}px, ${position.y}px)`,
      pointerEvents: 'none',
      left: -20,
      top: -20,
      width: 40,
      height: 40,
    }} />
  );
}

We are importing the useState and useEffect hooks. these hooks lets us maintain state and take care of external effects in our component

The useEffect hook has a handleMove event listener function. It takes e as an argument and sets the position of clientX and clientY properties of the event object

which is the X and Y coordinates of the mouse pointer. The useEffect hook adds an event listener function called the handleMove to the window Object that listens to the pointermove events

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat API and SDK.

We also have a clean up function that removes the event listener when the component is unmounted

Lastly we have a div element with a pink semi-transparent background that tracks where the pointer is moving

The element also has pointerEvents: none to avoid having the pointer interact with other element on the page

Conclusion

In this article we have explained how to use useEffect to connect to an external source ( and What we mean by an external source: External source is something that is not controlled by the react like an API or a Database etc)

We also gave a few examples and explained what is the role of the clean-up function and how the dependencies are required to be added in an array format to the setup

Note: This article was originally written on the DeadSimpleChat Blog: React useEffect: A complete guide with examples