I am new to React and Javascript as a whole. I am simply trying to access array indices after a fetch. I can log a specific index after a file update, but when I refresh the page, I get an 'Undefined' error. I feel as if I am doing something wrong with my state, but I don't know enough about React to debug this. if I attempt to access " users[0].name", I get the "TypeError: Cannot read properties of undefined (reading 'name') (anonymous function).
import React, { useEffect, useState } from "react";
import { Container, Card, Divider, Typography } from "@mui/material";
const RestData = () => {
const [data, setData] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users/")
.then((response) => response.json())
.then((data) => setData(data));
}, []);
return (
<Container>
{data.map((users) => {
return (
<Card
data={data}
key={users.id}
sx={{ width: "300px", mt: 2, background: "#ff9800" }}
>
<Typography variant="h6" color="seagreen">
{users.name}
</Typography>
<Divider />
{users.email}
<Divider />
{users.company.name}
<Divider />
{users.phone}
<Divider />
{users.website}
<Divider />
</Card>
);
})}
</Container>
);
};
export default RestData;
CodePudding user response:
Although I don't see this occurring in the code you posted, you are getting that particular error because you are trying to access .name
when the object
being accessed is undefined.
I presume you are trying to do something like data[0].name
.
The issue is, your data
array starts empty, so if you try to access any index of an empty array, it will be undefined
, you will get that error.
The solution is to make sure the data
array already has it's elements in before you access an index of it.
Now, there are many ways to do this. Because it doesn't seem to be a part of your code, it is hard to tell you the best way. But here is a couple:
1- Do an if check before attempting to access the property:
if (data[0]) {
console.log(data[0].name)
// do stuff
}
2- Check if the property exists first using the &&
operator:
For this case, the attempt to access the name
is only done if data[0]
is truthy.
console.log(data[0] && data[0].name)
3- Use optional chaining. This is the better one imo, since it allows you to skip the if and will only attempt to access a property if it is not undefined
.
console.log(data[0]?.name)
So now to put this in practice, here is a sample app:
const App = () => {
const [data, setData] = React.useState([]);
React.useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users/")
.then((response) => response.json())
.then((data) => setData(data));
}, []);
console.log("data", data);
return (
<div>
<div>
<h3>Example by accessing the index directly with Optional Chaining:</h3>
<p>{data[0] && data[0].name}</p>
</div>
<div>
<h3>Example with the map</h3>
{(data).map((d) => {
return <p>{d.name}</p>;
})}
</div>
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
CodePudding user response:
Since you're fetching the data at rendering time you don't have users[0].name
, so what I would suggest is to use the conditional operator ?
.
So you have something like this
data[0]?.name
What happens in this case is that typescript try to access the property name
at the given index, if the property is undefined
returns null otherwise returns the value.
I've also made a quick sandbox for demonstration.