Prevent empty arrays when fetching data from API (useEffect initial state) and is it the good architecture approach?

I’m trying to create a COVID Dashboard using disease.sh API (I’m learning Web dev and React atm).
I’m storing the global data in globalData and trying to get the countries list in countries. After that, my plan is to display it in a dropdown menu (Dropdown component).

My question : when getting datas, if I console.log, there is always an empty array (initial state I presume). Just wanted to know, as I’m learning all of this, if it was the correct approach :

  • having my fetching and states in App
  • passing them as props to my components to display data

And, is it possible to prevent that empty array phase ? Am I architecturing it the wrong way ?

Here is my App component :

const App = () => {
  const [globalData, setGlobalData] = useState([]);
  //const [countryData, setCountryData] = useState({});
  const [countries, setCountries] = useState([]);

  useEffect(() => {
    getCountriesData();
    getGlobalData();
  }, []);

  const getGlobalData = async () => {
    const response = await diseaseAPI.get("/v3/covid-19/all");
    setGlobalData(response.data);
  };

  const getCountriesData = async () => {
    const response = await diseaseAPI.get("/v3/covid-19/countries");

    const countries = response.data.map((country) => ({
      countryName: country.country,
      countryCode: country.countryInfo.iso2,
      countryFlag: country.countryInfo.flag,
    }));
    setCountries(countries);
  };

  return (
    <div>
      <ThemeProvider theme={darkTheme}>
        <CssBaseline />
        <AppBar position="static">
          <Toolbar>
            <Typography variant="h6">COVID-19 Tracker</Typography>
          </Toolbar>
        </AppBar>
        <Container maxWidth={false}>
          <h1>Worldwide data</h1>
          <Dropdown countries={countries} />
          <Grid
            container
            direction="row"
            justify="center"
            alignItems="center"
            spacing={3}
          >
            <Grid item xs>
              <InfoBox
                label="Total cases"
                total={numeral(globalData.cases).format()}
                cases={numeral(globalData.todayCases).format("+0,0")}
              />
            </Grid>
            <Grid item xs>
              <InfoBox
                label="Total deaths"
                total={numeral(globalData.deaths).format()}
                cases={numeral(globalData.todayDeaths).format("+0,0")}
              />
            </Grid>
            <Grid item xs>
              <InfoBox
                label="Recovered"
                cases={numeral(globalData.todayRecovered).format("+0,0")}
                total={numeral(globalData.recovered).format()}
              />
            </Grid>
          </Grid>
          <small>Last update: {convertUnixTime(globalData.updated)}</small>
        </Container>
      </ThemeProvider>
    </div>
  );
};

export default App;

My InfoBox component :

const InfoBox = ({ label, cases, total }) => {
  return (
    <>
      <Card>
        <CardContent>
          <Typography variant="h4" color="textSecondary" gutterBottom>
            {label}
          </Typography>
          <Typography variant="h5" color="textPrimary" gutterBottom>
            {total !== "0" ? total : "Loading..."}
          </Typography>
          <Typography variant="body2" color="textPrimary" gutterBottom>
            {cases !== "+0" ? `${cases} today` : "Loading..."}
          </Typography>
        </CardContent>
      </Card>
    </>
  );
};

export default InfoBox;

My Dropdown component :

const Dropdown = ({ countries }) => {
  //console.log(countries);
  //if (!countries) return <div>Loading...</div>;
  const renderedCountries = countries.map((country) => {
    return <li key={country.countryName}>{country.countryName}</li>;
  });

  return (
    <div>
      <ul>{renderedCountries}</ul>
    </div>
  );
};

Here is also the github repo. Thank you all, and sorry if it’s not clear enough, feel free to ask me to be more explicite !

1 thought on “Prevent empty arrays when fetching data from API (useEffect initial state) and is it the good architecture approach?”

  1. That the state of <App /> is empty ([]) at the beginning is normal bevhaviour. You initialize it with an empty arry (useState([])) and only then, afterwards, you call useEffect(() => {... which populates it. So don’t worry, this is normal behaviour in React and has nothing to do with your architecture, performance or what so ever. When you go further down the road and you application grows, you might have to check if your props contain the data you expect there to be and only execute your logic if the data is there.

    I would probably separating the fetching of the data from the <App /> component as the <App />component is the "highest" component you probably have in your Application. It is the entrypoint for your App and should not contain such logic as fetching data from an external API. In the long run, when your App grows, this won’t scale. I’d create component into which I put everything in <Container>...</Container> and the code needed to get the data <Dropdown /> and <InfoBox> need.

    Reply

Leave a Comment