简体   繁体   中英

API call in React "TypeError: Cannot read properties of undefined (reading 'map')"

I am trying to populate the list of objects with data from an array retrieved with an API call. I do get correct data (can console.log the object) but using it in code does not work. I have tried multiple solutions but nothing worked so far and I am stuck, before spending another 2 days on that I wanted to ask for your help. I am sure this is something simple I still haven't learned yet.

TypeError: Cannot read properties of undefined (reading 'map')

const EventCarousel = () => {
  const [data, setData] = useState([]);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setLoading(true);
    axios

      .get(
        "https://cdn.contentful.com/spaces/qqdjjpwbe10z/environments/master/entries?access_token=PRIVATE_TOKEN"
      )
      .then((res) => {
        console.log(res.data.items[0].fields.imageUrl);
        setData(res.data);
      })
      .catch((error) => {
        setError(error.message);
      })
      .finally(() => {
        setLoading(false);
      });
  }, []);

if (loading) {
    return <p>Data is loading...</p>;
  } else
    return (

 {data.items.map((item) => (
            <div>
              <Event
                imageUrl={item.fields.imageUrl}
                title={item.fields.title}
                text={item.fields.text}
                linkUrl={item.fields.linkURL}
                location={item.fields.location}
                date={item.fields.date}
              />
            </div>
          ))}

The JSON structure looks as follows:

{
"sys": {},
"total": 2,
"skip": 0,
"limit": 100,
"items": [
{
"metadata": {},
"sys": {},
"fields": {
"title": "Second Event",
"text": "This is decription of a second event",
"imageUrl": "https://i.imgur.com/ULO8mVt.png",
"linkUrl": "https://www.moabit.world",
"location": "Second Location",
"date": "second date"
}
},
{
"metadata": {},
"sys": {},
"fields": {
"title": "First Event",
"text": "This is first fetched text",
"imageUrl": "https://i.imgur.com/ULO8mVt.png",
"linkUrl": "https://www.facebook.com",
"location": "First location",
"date": "First date"
}
}
]
}

THANK YOU

It's because when your component gets mounted, It doesn't have data.items field as your initial data would be [] .

You need to first set your initial state to contain {} and then update data.items to behave conditionally.

Try following solution:

const EventCarousel = () => {
  const [data, setData] = useState({});
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setLoading(true);
    axios

      .get(
        "https://cdn.contentful.com/spaces/qqdjjpwbe10z/environments/master/entries?access_token=PRIVATE_TOKEN"
      )
      .then((res) => {
        console.log(res.data.items[0].fields.imageUrl);
        setData(res.data);
      })
      .catch((error) => {
        setError(error.message);
      })
      .finally(() => {
        setLoading(false);
      });
  }, []);

if (loading) {
    return <p>Data is loading...</p>;
  } else
    return (

 {data?.items?.length ? data.items.map((item) => (
            <div>
              <Event
                imageUrl={item.fields.imageUrl}
                title={item.fields.title}
                text={item.fields.text}
                linkUrl={item.fields.linkURL}
                location={item.fields.location}
                date={item.fields.date}
              />
            </div>
          )) : null}

You initial your state as an array useState([]) but you using it as an object data.items , either pick one of them:

const [data, setData] = useState({items: []});
setData(res.data)

// Or
const [data, setData] = useState([]);
setData(res.data.items)

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