Home > Software design >  How to stop useEffect from making so many requests? Empty Dependencies don't work
How to stop useEffect from making so many requests? Empty Dependencies don't work

Time:03-01

I have a component that updates a piece of state but I'm having issues with it

I have the state declared

const [data, setData] = useState([]);  

Then in my useEffect I am

useEffect(() => { 
  const fetchData = async () => {
    await axios
    .get(
      API_URL,
      {
        headers: {
          'Content-Type': 'application/json',
          'X-API-KEY': API_KEY
        },
        params:{
          "titleId": id
        }
      }
    )
    .then((response) => {
      setData(response.data.Item);
    })
    .catch((err) => {
      console.error("API call error:", err.message);
    }); 
  }  

  fetchData();         
  
}, [data, id])

If I declare "data" in my dependencies, I get an endless loop of requests which is obviously no good. But if I leave 'data' out from the dependencies it shows nothing, though I am successfully retrieving it in my network's tab and even when I {JSON.styringify(data)} in a div tag aI get the json content too. So the info is in the DOM, but it's not updating the components

How can I do this so I can make an initial request to load the data and not thousands of them?

I've tried the following:

  • a setTimeout on the callback function
  • the isCancelled way with a return (() => { callbackFunction.cancel(); })
  • And there is an Abort way of doing this too but I can't figure it out. Every example I've seen is for class components

Sorry for the vague code. I can't replicate this without lots of coding and an API. Thanks in advance

CodePudding user response:

You want to set the state and then check if is different. I use a custom hook for this which uses the useRef hook:

export function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}

const prevData = usePrevious(data);

I don't know what your data looks like, but build a conditional from it. Inside of your useEffect you'll need something like:

if (data !== prevData) fetchData()

or

if (data.id !== prevData.id) fetchData()

You'll then add prevData to you dependencies:

 [data, prevData, id]

CodePudding user response:

Do something like this, if that can help. I also used async/await so you can check that.

const App = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axios.get(API_URL, {
          headers: {
            'Content-Type': 'application/json',
            'X-API-KEY': API_KEY,
          },
          params: {
            titleId: id,
          },
        });
        setData(response.data.Item);
      } catch (err) {
        console.error('API call error:', err.message);
      }
    };

    fetchData();
  }, [id]);

  if (!data.length) return null;

  return <p>Yes, I have data</p>;
};

CodePudding user response:

obviously you will get an infinit loop ! you are updating the data inside your useEffect which means each time the data changes, triggers useEffect again and so on ! what you should do is change your dependencies depending on your case for example :

const [data, setData] = useState([])
const [fetchAgain, setFetchAgain] = useState(false)
useEffect(()=> {
   fetchData();
}, [])

useEffect(() => {
    if(fetchAgain) {
        setFetchAgain(false)
        fetchData();
    }
}, [fetchAgain])

now each time you want to fetch data again you need to update the fetchAgain to true

CodePudding user response:

So useEffects works with dependency.

With dependency - on changing dependency value useEffect will trigger

useEffect(() => {
    // code
}, [dependency])

With empty brackets - will trigger on initial of component

useEffect(() => {
    // code
}, [])

Without dependency and Brackets - will trigger on every state change

useEffect(() => {
    // code
})
  • Related