tarek hassan
tarek hassan

Reputation: 802

How to ensure API data is called and added with .then

I am getting data in useEffect and looping through it to add additional data.

I want to do some calculations on it after all data being added to results, I make the calculations inside if (response.data.next) but after that inside then when I try to access data it prints old data.

How can I make make sure all data added then be able to use it in then?

const [results, setResults] = useState([]);

  useEffect(() => {

    async function handleAPIRequest(url) {
      return await axios
        .get(url)
        .then(async (response) => {
          await setResults((results) => [...results, ...response.data.results]);
          if (response.data.next) {
            await handleAPIRequest(response.data.next);
          }
          return results;
        })
        .then(async () => {
          // this is where I want to use results
          console.log("resultss: ", results);
        });
    }

    handleAPIRequest(url)

  }, []);

Upvotes: 0

Views: 35

Answers (2)

Emanuele Scarabattoli
Emanuele Scarabattoli

Reputation: 4469

You should change your code in the following way:

const [results, setResults] = useState([]);

useEffect(() => {
  const handleAPIRequest = async url => {
    const lastResult = await axios.get(url);
    setResults([...results, ...lastResult.data.results]);
    const toLogResults =  [...results, ...lastResult.data.results];
    if(response.data.next) {
      await handleAPIRequest(response.data.next);
    } else {
      console.log("The final results are", toLogResults);
    }
  }
  handleAPIRequest(url)
}, []);

The main problem is that results in lines following setResults() are not updated immediately, so the value is the old one.

The toLogResults is used just to display the actual result, it is not needed.

Upvotes: 0

buzatto
buzatto

Reputation: 10382

I would suggest to keep consistency between async/await or chaining promises. your approach can cause multiple setResults, not sure if that's what you desire. Below, I offer a solution that might suit your needs:

useEffect(() => {
  async function handleAPIRequest(url, currentResults = []) {
    try {
      const response = await axios.get(url)
      const nextResults = [...currentResults, ...response.data.results];
      if (response.data.next) {
        return await handleAPIRequest(response.data.next, nextResults);
      }
      return nextResults;
    } catch (error) {
      throw error;
    }
  }

  try {
    const finalResults = await handleAPIRequest(url);
    setResults(results => [...results, ...finalResults]);      
  } catch (error) {
    // here you can handle error response
    console.log(error);
  }
}, []);

// to do something after results state is updated use another use effect to accomplish that
useEffect(() => {
// do something on updated results state
}, [JSON.stringify(results)]);

Upvotes: 1

Related Questions