Skip to content
Search

React:useEffect

lastmod 2024-01-02created 2022-09-198 edits

Usage

Run on every render

No second argument.

useEffect(() => {
  // ...
});

Run only on the first render

Pass an empty array as the second argument.

useEffect(() => {
}, []);

Run on the first render and whenever a dependency variable changes

Pass an array containing the dependency variables as the second argument.

useEffect(() => {
}, [value1, value2, ...]);

Simply put, add every external variable used inside the useEffect callback to the dependencies. (Strictly speaking, variables that affect the logic. Variables with no effect are usually left out.)

Clean Up

Return a function from inside the useEffect() function.

useEffect(() => {
  return () => {
    // cleanup code ...
  };
}, [value1, value2, ...]);
  • Runs on unmount.
  • Runs just before the useEffect() of the next render runs.

Sample example

You need loading, data, and error cases.

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

function Profile({ userId }) {
  const [loading, setLoading] = useState(true);
  const [user, setUser] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    window
      .fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
      .then((res) => res.json())
      .then((user) => {
        setUser(user);
        setLoading(false);
      })
      .catch((error) => {
        setError(error);
        setLoading(false);
      });
  }, [userId]);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;

  return (
    <ul>
      <li>id: {user.id}</li>
      <li>email: {user.email}</li>
      <li>name: {user.name}</li>
      <li>phone: {user.phone}</li>
      <li>website: {user.website}</li>
    </ul>
  );
}

Async ver

Don't call it directly like useEffect(async () => {...});, because that returns a Promise object. Instead, call it inside the callback:

useEffect(() => {
  (async () => {
    // TODO ...
  })();
}, [param])

Making fetch abortable

useEffect(() => {
  const controller = new AbortController();
  const signal = controller.signal;

  fetch(`/api/users/${id}`, {signal})
    .then(res => res.json())
    .then(data => {
      setUser(data);
    });

  return () => {
    controller.abort();
  };
}, [id])

See also

Favorite site

author Zer0 sitemap