Sabrina Reyes
Sabrina Reyes

Reputation: 25

Infinite loop when pushing into array using UseState()?

I would like to store the data of a response into an array for reuse. I am using Axios for this. The issue I receive is that when I push into the array, it loops getBoroughAndId() and keeps pushing into the array. I can tell because I get a console.log() response where it keeps telling me I am making too many requests. Any advice? Thanks.

Edit: After taking another gander, I think the issue is that the id is always changing when running getBoroughAndId. I'm not sure how to stop this.

import React, { useEffect, useState } from 'react';
import { airtableApi } from '../services/api/airtable';
import { BoroughDay, BoroughGroup } from '../types/api';

const IndexPage = () => {
  const [boroughs, setBoroughs] = useState<BoroughDay[]>([]);
  const [boroughGroups, setBoroughGroups] = useState<BoroughGroup[]>([]);

  const getBoroughsAndDays = () => {
    airtableApi
      .getBoroughsAndDays()
      .then((response) => {
        setBoroughs(response);
      })
      .catch(() => { });
  };

  const getBoroughAndId = (id: string) => {
    airtableApi
      .getBoroughAndId(id)
      .then((response) => {
        console.log(response);
        setBoroughGroups(arr => [...arr, response])
        return response;
      })
      .catch(() => { });
  }

  useEffect(() => {
    getBoroughsAndDays()
  }, [boroughGroups])

  return (
    <>
      {boroughs.map((data) => {
        getBoroughAndId(data.id);
      })}
    </>
  )
}

export default IndexPage

Here is my corrected code. It works a lot better now, with less nonsense and everything being done in the first function.

import React, { useEffect, useState } from 'react';
import { airtableApi } from '../services/api/airtable';
import { BoroughDay, BoroughGroup } from '../types/api';

const IndexPage = () => {

  const [boroughs, setBoroughs] = useState<BoroughDay[]>([]);
  const [boroughGroups, setBoroughGroups] = useState<BoroughGroup[]>([]);

  const getBoroughsDays = () => {
    airtableApi
      .getBoroughsAndDays()
      .then((response) => {
        setBoroughs(response.records);
        response.records.map((data) => {
          setBoroughGroups(arr => [...arr, {id: data.id, "Borough": data.fields["Borough"]}])
        })
      })
      .catch(() => { })
  }

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

  return (
    <>
      {boroughGroups.map(data => <div>{data.id} {data.Borough}</div>)}
    </>
  )
}

export default IndexPage

Upvotes: 1

Views: 705

Answers (2)

Siddharth Agrawal
Siddharth Agrawal

Reputation: 116

In order to tell you the mistake you are committing, I will tell you the whole flow of your program.

  1. First of all when component mounts, useEffect will be called, which will call the getBoroughsAndDays function.

Note: boroughGroups in dependency array in useEffect is causing an infinite loop

  1. This function (getBoroughsAndDays()) will update the value of boroughs(using setBoroughs)

  2. Now since the state updated the function will re render, hence output will be shown on the screen

  3. Now observe, here you are calling "getBoroughAndId(data.id)" function (inside map function), which is updating the value of boroughGroups(using setBoroughGroups)

  4. Now since the value of boroughGroups have changed, the useEffect method will be called, which will again trigger the "getBoroughsandDays()" function, repeating the whole process again, so that is the reason, it is creating infinite loop.

Note: When any value inside dependency array changes useEffect will be called.

Solution: I don't know what functionality you want to achieve but remove "boroughGroups" dependency from useEffect (In this way it will behave like componentDidMount).

Upvotes: 1

Prashant Vishwakarma
Prashant Vishwakarma

Reputation: 315

You have a useEffect hook that updates state: boroughs whenever value of state: boroughGroups changes.

In the return statement, you iterate through boroughs and update boroughGroups. Back to the first statement.

To stop this infinite loop, stop updating boroughGroups, that triggers useEffect everytime.

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

Upvotes: 0

Related Questions