Accepted answer

useeffect runs after your component is mounted which means rates is just an empty array that doesn't have a property called rates


try to use

const [rates, setrates] = usestate({rates:[]});

or make a loading indicator for example

const ratescard = () => {

    const [rates, setrates] = usestate([]);
            .then(ratesresponse => ratesresponse.json())
            .then(rates => setrates(rates));

    if(rates.length === 0) {
        return <h1> loading </hi>
    return (
        <div classname="rates">
                rate => <button variant="outlined">


first, your state is equal to [] in the first render you're trying to do the following: object.keys([].rates) and obviously here rates doesn't exist on the array it ends up doing object.keys(undefined) which results to the error.

so the solution to me is instead of setting the whole object to rates you can just set the rates object of the response by destructuring (cf.

  useeffect(() => {
      .then((ratesresponse) => ratesresponse.json())
      .then(({ rates }) => setrates(rates));
  }, []);


your default value for rates should be an empty object with rates property set to an empty array ({rates: []}).

by saying the following object.keys(rates.rates).map you're going with the assumption that the rates will be an object, and rates.rates will be an array.

it works the "first" time due to how hot reloading works, because when you save your files, it injects codes to the browser and not remounting the entire app. thus, your app will continue from where it left off before, even if it crashed on the previous load..

change your state definition to the following: const [rates, setrates] = usestate({rates:[]});

this will ensure when your app tries to run object.keys(rates.rates).map it doesn't crash because you have an array to iterate not null/undefined

Related Query

More Query from same tag