Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

217
Vistas
Why my useEffect runs infinitely when promise gets rejected but only once when it gets fulfilled?

I am trying to fetch data from a mock backend created using JSON-server with the help of Axios. Now when the response status is 200 i.e., data fetched successfully the state of my success variable changes to true. The useEffect runs only once and message toast appears only once. But now when there is an error while fetching the data the useEffect runs infinitely and toast starts appearing non-stop one after another. Can someone explain to me why is this happening and how am I able to solve this issue?

Below is the code I have written.

import React, { useState, useEffect } from 'react';
import Loader from './../components/Loader';
import axios from 'axios';
import { toast } from 'react-toastify';

const PostsTD = () => {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState({
    status: false,
    message: '',
  });
  const [success, setSuccess] = useState(false);

  const getPosts = () => {
    axios
      .get('http://localhost:5050/posts')
      .then((res) => {
        setPosts(res.data);
        setLoading(false);
        if (res.status === 200) setSuccess(true);
      })
      .catch((error) => {
        setLoading(false);
        setError({ status: true, message: error.message });
      });
  };

  useEffect(() => {
    getPosts();

    if (error.status) {
      toast.error(error.message);
    }

    if (success) toast.success('Success!');
  }, [success, error]);

  if (loading) {
    return (
      <div className="px-28 text-center py-12">
        <Loader />
      </div>
    );
  }

  return (
    <div className="md:px-28 px-6">
      <h1 className="text-center font-extrabold text-gray-400 my-4 text-4xl">POSTS FETCHED USING AXIOS</h1>

      {posts && posts?.length > 0 ? (
        <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 py-2 px-3 bg-red-500">
          {posts?.map((post, idx) => {
            return (
              <div key={idx} className="p-3 bg-red-200 text-gray-900 rounded-md">
                <h2 className="font-semibold text-xl">{post.title}</h2>
                <p className="font-normal my-3">{post.body}</p>
              </div>
            );
          })}
        </div>
      ) : (
        <h1>NO posts to render</h1>
      )}
    </div>
  );
};

export default PostsTD;

about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

  useEffect(() => {
    getPosts();

    if (error.status) {
      toast.error(error.message);
    }

    if (success) toast.success('Success!');
  }, [success, error]);

Since error is in the dependency array, any time the error changes, this effect will run. So the error changes, which causes you to get the posts, which causes the error to change, etc.

I would split this up into separate effects; one to kick off the load, and another to do the toasts:

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

useEffect(() => {
  if (error.status) {
    toast.error(error.message);
  }

  if (success) toast.success('Success!');
}, [sucess, error]);
about 4 years ago · Juan Pablo Isaza Denunciar

0

As others have mentioned before, your problem is with your useEffect triggering another getPosts call when it was only supposed to react to a change in success or error variables.

When doing API calls inside an effect, please consider these: (#1 is based on personal opinion)

  1. Preferably handle the promise inside the effect (or make 2 separate effects: 1 to make the call and 1 to react to success / error)
  2. Add a cleanup function to handle promise cancellation in case of a cleanup (https://beta.reactjs.org/learn/synchronizing-with-effects#fetching-data)

This is how I would probably structure it:

useEffect(() => {
    const controller = new AbortController();
    axios
        .get('http://localhost:5050/posts', {
            signal: controller.signal
        })
        .then((res) => {
            setPosts(res.data);
            setLoading(false);
            if (res.status === 200) setSuccess(true);
        })
        .catch((error) => {
            setLoading(false);
            setError({ status: true, message: error.message });
        });

    return () => {
        controller.abort();
    }
}, []);
about 4 years ago · Juan Pablo Isaza Denunciar

0

Your useEffect has error as dependency and getPosts in its logic, so, if getPosts sets error (as it does) it creates an infinite loop.

useEffect => getPosts => setError => useEffect ...

You can resolve this by deleting the error dependency of your useEffect, if you still want to refetch data, I think you should directly call getPosts in getPosts in a setTimeout for example.

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda