React: useEffect() Hook

React: useEffect() Hook

The useEffect Hook allows you to perform side effects in your components. It takes two arguments, first is setup function, a function with your effect's logic. and second is dependencies, which is an optional argument

useEffect(<setup>, <dependencies>)

Example:

Dependencies is an optional argument, so when you don't pass any dependency, useEffect will run after every render.

import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";
function Timer() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
    }, 3000);
  });
  return <h1>Count:{count}</h1>;
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Timer />);

https://codesandbox.io/p/sandbox/useeffectexample-qqpxw2?file=%2Fsrc%2Findex.js%3A13%2C15

In the above example, count will be increase by 1 after every 3 seconds.

But sometimes these side effects need to be control, for that, we pass the second argument Dependency Array.

To run the useEffect at the initial render only, we pass an empty array.

Example:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";
function Timer() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
    }, 2000);
  }, []);
  return <h1>Count: {count}</h1>;
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Timer />);

https://codesandbox.io/p/sandbox/useeffectexample-2-v4ft5v?file=%2Fsrc%2Findex.js%3A9%2C10

In some condition useEffect is dependent on some variable, we have to pass that variable in the dependency array to run the useEffect when that variable gets update. If there are multiple dependencies, then they should be included in the dependency array.

Example:

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
function Counter() {
  const [count, setCount] = useState(0);
  const [total, setTotal] = useState(0);
  const handleIncrement = () => {
    setCount(count + 1);
  };
  const handleDecrement = () => {
    setCount(count - 1);
  };
  useEffect(() => {
    setTotal(() => count * 2);
  }, [count]);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleIncrement}>Increment</button>
      <button onClick={handleDecrement}>Decrement</button>
      <p>Total: {total}</p>
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Counter />);

https://codesandbox.io/p/sandbox/useeffectexample-3-y2njcm?file=%2Fsrc%2Findex.js%3A10%2C23

Some effects require cleanup, to avoid memory leaks. Some effects that are no longer needed should be disposed. We can do this by including the return function at the end of the useEffect hook.

Example:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";
function Counter() {
  const [count, setCount] = useState(0);
  const [total, setTotal] = useState(0);
  useEffect(() => {
    let t = setTimeout(() => {
      setCount((count) => count + 1);
    }, 2000);
    return () => clearTimeout(t);
  });
  useEffect(() => {
    setTotal(() => count * 2);
  }, [count]);
  return (
    <div>
      <p>Count: {count}</p>
      <p>Total: {total}</p>
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Counter />);

https://codesandbox.io/p/sandbox/useeffectexample-4-dvdl3m?file=%2Fsrc%2Findex.js%3A7%2C10

Read more