Home > Enterprise >  How to clear previous api call? (React)
How to clear previous api call? (React)

Time:10-12

I'm trying to find a proper way to "clear" my first fetch request if a second one is made.

I have this:

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

const callAPI = async () => {
    const api = await fetch(
      `my API`
    );
    const data = await api.json();
    setData(data);

The user can call the same api again to request similar or different date for a second, third, fourth time.... and I'm having issues with rendering information after the first call. I receive the info from the fetch request but React won't load the info properly or at all. I'm wondering if there is a proper way to do something like this:

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

const callAPI = async () => {
 **  clearFetch() **
    const api = await fetch(
      `my API`
    );
    const data = await api.json();
    setData(data);

CodePudding user response:

Yes, there is. The fetch() function can be canceled. You use an AbortController's signal object. The details can be seen in this answer.

I will assume you have your call to fetch() inside a useEffect().

let abortC = null;
export default MyComponent = () => {
    useEffect(() => {
        abortC?.abort();
        abortC = new AbortController();
        var x = async () => {
            try {
                var response = await fetch('blah', { signal: abortC.signal });
                setSomeState(await response.json());
            }
            catch (ex) {
                // Whatever.
            }
        };
        x();
    }, [dependencies]);
    return ...
}

UPDATE: Edited to take the declaration of abortC out to the top level so it is properly enclosed. This would be in response of @EndlessCodebase's comment. Many thanks for the observation.

CodePudding user response:

you can use useEffect's cleanup function to clear previous call. In below code snippet api call will be ignored if add-dependency-which-causes-to-rerun changes within 500ms. Hope it helps!

useEffect(() => {
    const getData = setTimeout(async () => {
      const api = await fetch(
        'my API'
      );
      const data = await api.json();
      setData(data);

    },500)
    return () => clearTimeout(getData)
    
  }, [<add-dependency-which-causes-to-rerun>])

CodePudding user response:

if we are fetching data only on button click then above solution may NOT be a good option. I think you need something like this.

import React, { useEffect, useState, useRef } from 'react';

const FetchDetails = () => {
  const [inputIsChanged, setTnputIsChanged] = useState(false);
  const [prevInput, setPrevInput] = useState('');
  const inputRef = useRef('');
  const initialRender = useRef(true);

  const clickHander = () => {
    const currentValue = inputRef.current.value;

    setTnputIsChanged(inputRef.current.value !== prevInput);
    setPrevInput((prevState) =>
      prevState === currentValue ? prevState : currentValue
    );
  };

  useEffect(() => {
    (async () => {
      if (initialRender.current || !inputIsChanged) {
        initialRender.current = false;
        return;
      }

      const response = await fetch(
        'https://jsonplaceholder.typicode.com/todos/1'
      );
      const data = await response.json();
      console.log(data);
    })();
  }, [inputIsChanged]);

  return (
    <>
      <input type="text" ref={inputRef} />
      <button onClick={clickHander}>Fetch Details</button>
    </>
  );
};

export default FetchDetails;
  • Related