0

Hi i am trying to show the data from a json url in ReactJS by inputing all the data to an array variable but i can't use the array in the JSX part because the array is not yet populated while rendering i try'd many things but i always end up in a promise loop where i need a promise to get the data from the other one. THE CODE:

let arry = [];
  let ar = [];

  async function getdriver() {
    const response = await fetch("https://ergast.com/api/f1/current/drivers.json");
    ar = await response.json();
    ar.MRData.DriverTable.Drivers.forEach((element) => {
      arry.push(element);
    });
    return arry;
  }

  getdriver();

  console.log(arry);// the array is populated but i think it waits for it before showing
  console.log(arry.lenght); //lenght is 0

JSX:

return (
    <div>
      <Menu />
      <div style={{ textAlign: "left" }}>
        <h4>ff</h4>
        <Button >change</Button>
        <br></br>
        <i>{arry[0].code}</i>// error ' Cannot read property 'code' of undefined ' so arry is empty? 
      </div>
    </div>
  );
NAYN9
  • 55
  • 8
  • instead of returning an array, save the data in the state of the component and inside the JSX, use `map()` method on the array saved in the state. See: [Using the State Hook](https://reactjs.org/docs/hooks-state.html) – Yousaf Jul 23 '21 at 10:48
  • There are some "special" things going on there :). You need to `await` the `getdriver()` method. – Lars Jul 23 '21 at 10:53

2 Answers2

0

Fetching data is a side-effect, and then you will need to store this data as state, so you will need to make use of two kinds of hooks (assuming you are creating function components):

Your asynchronous code will be called in useEffect, and when the call is completed you will save the result as the component's state using useState.

The code will look similar to the example below (I've kept as much as your code as possible, but renamed some functions and variables, and added some comments, to make this useful for as many other readers as possible):

import { useState, useEffect } from "react";

// this can exist outside the component
// it can even be in a different file
async function fetchDrivers() {
  const response = await fetch(
    "https://ergast.com/api/f1/current/drivers.json"
  );
  const data = await response.json();
  return data.MRData.DriverTable.Drivers;
}

function YourComponent() {
  // we declare the state, initially it's an empty array
  const [drivers, setDrivers] = useState([]);

  // we declare the effect that runs exactly once,
  // when the component is mounted
  useEffect(() => {
    fetchDrivers().then(setDrivers);
  }, []);

  // we print the code for all drivers
  // mapping the drivers array to JSX.
  // notice the key attribute, this is required with map
  // to uniquely identify each element
  return (
    <div>
      <Menu />
      <div style={{ textAlign: "left" }}>
        <h4>ff</h4>
        <Button>change</Button>
        <br></br>
        {drivers.map((driver, index) => (
          <p key={index}>
            <i>{driver.code}</i>
          </p>
        ))}
      </div>
    </div>
  );
}
Andrei
  • 1,723
  • 1
  • 16
  • 27
  • 1
    Thank you very much This worked and i understand what i had to Do. Thank you everyone else for you help – NAYN9 Jul 23 '21 at 11:19
0

When you want to show data that is fetched from a API on first render you should put the API call in useEffect and give an empty array as a dependency to useEffect while setting the array as a state value for example:

 import {useState, useEffect} from 'React';

 function YourComponent(){
  const [array, setArray] = useState([]);

  useEffect(()=>{getDriver().then((array)=>
  {setArray(array)})}
  ,[])
 }

this is just an example, in getDriver() after you get the result of the API call you should set array using setState() to tell React to re-render after that value was changed but here when you put it in useEffect it will only be triggered on first render.

Sid Barrack
  • 1,235
  • 7
  • 17