简体   繁体   中英

"TypeError: listOfTours.map is not a function" when try to map over Array

I'm trying to display my listOfTours as individuals divs's in react, but I'm getting the following error:

TypeError: listOfTours.map is not a function

for the first 1 or 2 seconds it displays everything correctly but then the error comes up

My Array:

const [listOfTours, setListOfTours] = useState([
    {
      tour_date: "2020-04-24",
      tour_distance: 15,
      tour_duration: 60,
      tour_elevation_down: 245,
      tour_elevation_up: 245,
      tour_name: "Fahrradtour 24.04.2020 19:07",
      tour_sport: "mtb",
    },
    {
      tour_date: "2020-04-23",
      tour_distance: 34,
      tour_duration: 143,
      tour_elevation_down: 426,
      tour_elevation_up: 426,
      tour_name: "Fahrradtour 23.04.2020",
      tour_sport: "mtb",
    }
  ]);

My Code to Map over the Array:

return (
    <div>
      <div className="tourDisplay">
        {listOfTours.map((tour) => {
          return (
            <div>
              <div>Tourname: {tour.tour_name}</div>
              <div>...other values</div>
            </div>
          );
        })}
      </div>
    </div>
  );

It seems to have something todo with how i get my data to react

useEffect(() => {
    axios
      .get("/api/all-tours", {
        headers: {
          "x-access-token": localStorage.getItem("token"),
        },
      })
      .then((response) => {
        if (response.data.status === "error") {
          console.log(response.data.status);
        } else {
          setListOfTours(response.data);
        }
      });
  });

Since you're returning your data that you put into the State from an asyncrhonous call, it happens that when you invoke the function, your state is empty and the map doesn't find any data. You can solve easily this problem in different way; one of them could be use a loading state .

const [loading, setLoading] = useState(true);

Then you can modify your useEffect like that:

useEffect(() => {
    axios
      .get("/api/all-tours", {
        headers: {
          "x-access-token": localStorage.getItem("token"),
        },
      })
      .then((response) => {
        if (response.data.status === "error") {
          console.log(response.data.status);
        } else {
          setListOfTours(response.data);
        }
      }).then(_ => {
         setLoading(false);
      });
  });

And on the return you should add this:

if(loading) return <p>Loading...</p>
else return (
  <div>
    <div className="tourDisplay">
      {listOfTours.map((tour) => {
        return (
          <div>
            <div>Tourname: {tour.tour_name}</div>
            <div>...other values</div>
          </div>
        );
      })}
    </div>
  </div>
);

Eventually, you can move the loading near the map function, so:

{loading ? <p>Loading...</p>
  : (listOfTours.map((tour) => {
        return (
          <div>
            <div>Tourname: {tour.tour_name}</div>
            <div>...other values</div>
          </div>
        );
}))}

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