简体   繁体   中英

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?

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

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])

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM