rgdzv
rgdzv

Reputation: 505

How do I use async/await with Array.filter properly in React?

I'm creating just a simple currency converter (React + Typescript). Here is my component code:

const App = () => {

  const [countries, setCountries] = useState<Array<CountriesProps>>([])
  const [currencies, setCurrencies] = useState<Currencies>({})
  
  const filteredCountries = async () => {
      const { data } = await axios.get('https://restcountries.eu/rest/v2/all')
      const answer: Array<CountriesProps> = data
      const filtered = answer.filter(country => {
        for (let i in currencies) {
          if(i === country.currencies[0].code) {
            return country
          }
        }
      })
      setCountries(filtered)
  }
  
  useEffect(() => {
    axios
      .get('https://api.frankfurter.app/currencies')
      .then(res => {
        setCurrencies(res.data)
      })
      .catch(err => {
        console.log(err)
      }) 
  }, [])

  useEffect(() => {
    filteredCountries()
  }, [])

  return (
    ...
  )
}

export default App

I come across the problem, during launching the app. After getting currencies information from the server I need to fetch countries information. After getting countries I need to filter them and put them in my state (countries) and send it to another component and so on. But during launch of the app filter function doesn't work and I got no filtered countries and so I don't have any info in my state. I think that filter function needs to be an asynchronous, so we need to wait before setting our state through setCountries function. How to do it properly in my case or I did all the logic wrong?

Upvotes: 0

Views: 1364

Answers (3)

Yevhen Horbunkov
Yevhen Horbunkov

Reputation: 15530

As long as requested countries rely on fetched currencies and you don't seem to be using one without the another, you may stack .get()-requests accordingly or use respective async...await alternative:

fetchData = async () => {
      const currenciesResponse = await axios.get(currenciesEndpoint),
        currenciesData = await currenciesResponse.data,
        countriesResponse = await axios.get(countriesEndpoint),
        countriesData = await countriesResponse.data,
        filteredCountriesData = countriesData.filter(_country => {
          const {
            currencies: [{ code }]
          } = _country;
          return currenciesData[code];
        });
      setCurrencies(currenciesData);
      setCountries(filteredCountriesData);
    }

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

Following is a full-blown demo as a proof-of-a-concept

Upvotes: 1

Taghi Khavari
Taghi Khavari

Reputation: 6582

try using this:


const App = () => {

  const [countries, setCountries] = useState<Array<CountriesProps>>([])
  const [currencies, setCurrencies] = useState<Currencies>({})
  
  const filteredCountries = async () => {
      const res = await axios.get('https://api.frankfurter.app/currencies')
      // you don't need a state for currencies but in case you find a use case for it,
      // you're just setting the currencies here for future use cases.
      setCurrencies(res.data);
      const { data } = await axios.get('https://restcountries.eu/rest/v2/all')
      const answer: Array<CountriesProps> = data
      const filtered = answer.filter(country => {
        for (let i in res.data) {
          if(i === country.currencies[0].code) {
            return country
          }
        }
      })
      setCountries(filtered)
  }

  useEffect(() => {
    filteredCountries()
  }, [])

  return (
    ...
  )
}

export default App

Upvotes: 0

Nilesh Patel
Nilesh Patel

Reputation: 3317

See if this helps.

const [countries, setCountries] = useState<Array<CountriesProps>>([])
  const [currencies, setCurrencies] = useState<Currencies>({})
  
  const filteredCountries = async () => {
      const { data } = await axios.get('https://restcountries.eu/rest/v2/all')
      const answer: Array<CountriesProps> = data
      const filtered = answer.filter(country => {
        return currencies[country.currencies[0].code]
      })
      setCountries(filtered)
  }
  
  useEffect(() => {
    axios
      .get('https://api.frankfurter.app/currencies')
      .then(res => {
        setCurrencies(res.data)
      })
      .catch(err => {
        console.log(err)
      }) 
  }, [])

  useEffect(() => {
    filteredCountries()
  }, [currencies])

Upvotes: 0

Related Questions