Krzysztof Mansz
Krzysztof Mansz

Reputation: 113

Infinite loop in useEffect when setting state

I've got a question about useEffect and useState inside of it. I am building a component:

const [id, setId] = useState(0);
const [currencies, setCurrencies] = useState([]);

...
useEffect(()=> {
const getCurrentCurrency = async () => {
            const response = await fetch(`https://api.exchangeratesapi.io/latest?base=GBP`);
            const data = await response.json();
            const currencyArray = [];
            const {EUR:euro ,CHF:franc, USD: dolar} = data.rates;
            currencyArray.push(euro, dolar/franc,1/dolar);
            console.log("currencyArray", currencyArray);
             setCurrencies(currencies => [...currencies, currencyArray]);
          }
          getCurrentCurrency();
    }, [id, currencies.length]);

Which is used for making a new API request when only id change. I need to every time that ID change make a new request with new data. In my case now I have infinite loop. I try to use dependencies but it doesn't work as I expected.

Upvotes: 0

Views: 384

Answers (2)

Dennis Vash
Dennis Vash

Reputation: 53874

You changing a value (currencies.length), which the useEffect depends on ([id, currencies.length]), on every call.

Therefore you cause an infinite loop.

useEffect(() => {
  const getCurrentCurrency = async () => {
    // ...
    currencyArray.push(euro, dolar / franc, 1 / dolar);

//                    v The length is changed on every call
    setCurrencies(currencies => [...currencies, currencyArray]);
  };
  getCurrentCurrency();
//                    v Will called on every length change
}, [id,currencies.length]);

You don't need currencies.length as a dependency when you using a functional useState, currencies => [...currencies, currencyArray]

useEffect(() => {
  const getCurrentCurrency = async () => {
    ...
  }
  getCurrentCurrency();

}, [id]);

Moreover, as it seems an exchange application, you might one to use an interval for fetching the currency:

useEffect(() => {
  const interval = setInterval(getCurrency, 5000);
  return () => clearInterval(interval);
}, []);

Upvotes: 1

Eslam Abu Hugair
Eslam Abu Hugair

Reputation: 1208

you can just call the useEffect cb one the component mounted:

useEffect(()=>{
 //your code
 // no need for checking for the updates it they are inside the component
 }, []);

Upvotes: 0

Related Questions