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
CodePudding user response:
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}
CodePudding user response:
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)