Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React useEffect() Infinite loop

I was trying to replicate a personal project to set a Spinner loader while the data fetch is being load but I got another error before.

I was reading in other questions like this one, that in order to avoid a useEffect() infinite loop I have to add an empty array to the end, but still it doesn't work.

This is my code, it just re-renders infinitely despite the empty array added.

src/components/Users.js

import React, { useState, useEffect, useContext } from "react";
import GlobalContext from "../context/Global/context";

export default () => {
  const context = useContext(GlobalContext);
  const [users, setUsers] = useState([]);

  async function getUsers() {
    context.setLoading(true);
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    if (response.ok) {
        context.setLoading(false);
        const data = await response.json();
        setUsers(data);
    } else {
        console.error('Fetch error');
    }
  }

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

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
};

This is the non-working Sandbox, I am not sure why this is happening, any comments are appreciated.

like image 299
Maramal Avatar asked Jan 17 '26 08:01

Maramal


2 Answers

The problem is you keep mounting and then umounting the Users component. The <App> renders, and loading is false, so it renders <Users>. Since Users rendered its effect gets run which immediately sets loading to true.

Since loading is now true, <App> rerenders, and no longer has a <Users> component. You have no teardown logic in your effect, so the fetch continues, and when it's done, it sets loading to false and sets users to the data it got. Trying to set users actually results in this error in the console, which points out that Users is unmounted:

proxyConsole.js:64 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in _default (at App.js:25)

And now that loading has been set to false, the process repeats.

The solution to this is to have the data loading be in a component that stays mounted. Either change App to not unmount Users, or move the fetching up to App and pass the data as a prop.

like image 56
Nicholas Tower Avatar answered Jan 19 '26 22:01

Nicholas Tower


I think the issue is because of

context.setLoading(false);

just remove this line from your getUsers function and add a separate useEffect hook.

useEffect(() => {
   context.setLoading(false);
}, [users]) //Run's only when users get changed
like image 26
ravibagul91 Avatar answered Jan 19 '26 21:01

ravibagul91