0

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.

5
  • why do you need currencies.length1 if you only want to update when ID change Commented Oct 20, 2019 at 11:09
  • even if have only id dependency there is infinite loop. I change the state inside useEffect so this is the cause but I don't know how to workaround it in dependency. I try to use multiple dependencies ( this is why i add currencies.length) but it doesn't work Commented Oct 20, 2019 at 11:13
  • first line of my snippet. Commented Oct 20, 2019 at 11:19
  • where does id come from? Commented Oct 20, 2019 at 11:19
  • const [id, setId] = useState(0); and then i change it somewhere in the handler for go between the slides in slider like this: const goToPrevSlide = () => { id === 0 ? setId(2) : setId(id-1); } const goToNextSlide = () =>{ id === 2 ? setId(0) : setId(id+1); } Commented Oct 20, 2019 at 11:20

2 Answers 2

1

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);
}, []);
Sign up to request clarification or add additional context in comments.

3 Comments

Ok but why this is not working if i have only one dependency (id). My logic is described here: 1. When I mount component I would like to update default current state with currencies. 2. when i click button which change my id state i want to make new API request (by useEffect) and then I invoke my state once again with updated currencies from API.
Thats should work, just be sure on changing the id its different from the previous value
Working only if I update state directrly by using: currencies.push(euro, dolar/franc,1/dolar); not by setCurrencies(currencies => [...currencies, currencyArray]);
0

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
 }, []);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.