Home > Enterprise >  Accessing array indices in React
Accessing array indices in React

Time:12-13

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.

  • Related