Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

218
Views
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 answers
Answer question

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!