use ES6 .map() on multiple times nested objects for react components

Viewed 1551

How can I iterate through this object using .map():

state = { 
      contacts: [
        { "id":1,
           "name":"Leanne Graham",
           "email":"Sincere@april.biz",
           "address":{
              "street":"Kulas Light",
              "city":"Gwenborough",
              "geo":{
                 "lat":"-37.3159",
                 "lng":"81.1496"
              }
           },
           "phone":"1-770-736-8031",
        },
        { "id":2,
           "name":"Ervin Howell",
           "email":"Shanna@melissa.tv",
           "address":{
              "street":"Victor Plains",
              "city":"Wisokyburgh",
              "geo":{
                 "lat":"-43.9509",
                 "lng":"-34.4618"
              }
           },
           "phone":"010-692-6593",
        }
     ]
    }

so map over the contacts will work because is an array and all data like id, name, email and phone is accessible but if I want to iterate over the address, is crashing. I have used some example like:

render(){
  const {contacts} = this.state
  return(
    <>
       {Object.keys(contacts.address).map((address, index) => (
          <span className="d-block" key={index}>{contacts.address[address]}</span>
        ))}
    </>
  );
}

which should work with address but is crashin on geo{} and at this point I have lost the signal.

Anyone can give me an ideea ?

3 Answers

I don't think is a matter as long as it displays them

After you mapped the contacts you can excess the addresses properties as you like:

const contacts = [
  {
    id: 1,
    name: "Leanne Graham",
    email: "Sincere@april.biz",
    address: {
      street: "Kulas Light",
      city: "Gwenborough",
      geo: {
        lat: "-37.3159",
        lng: "81.1496",
      },
    },
    phone: "1-770-736-8031",
  },
  {
    id: 2,
    name: "Ervin Howell",
    email: "Shanna@melissa.tv",
    address: {
      street: "Victor Plains",
      city: "Wisokyburgh",
      geo: {
        lat: "-43.9509",
        lng: "-34.4618",
      },
    },
    phone: "010-692-6593",
  },
];

const addresses = contacts.map(({ address, id }) => ({
  id,
  ...address,
}));

console.log(addresses);

Like rendering them:

addresses.map(({ street, city, id }) => (
  <span className="d-block" key={id}>
    {street}:{city}
  </span>
))

This should help:

const address = contacts[0].address;

<>
  {Object.keys().map((addressKey, index) => (
    <span className="d-block" key={index}>
      {typeof address[addressKey] === "object"
        ? Object.keys(address[addressKey]).map(e => (
            <span>{address[addressKey][e]}</span>
          ))
        : contacts[0].address[address]}
    </span>
  ))}
</>;

You can map over an array because you expect it to have consistent values through each element, but that is not really the case for object. All the values are different and have different meaning. Also, your span will not be able to display objects, it will only primitive values such as strings or numbers

You can do what you want to achieve manually.

const { contacts } = this.state;
return (
  <>
    {contacts.map(({ address }, id) => {
      return (
        <React.Fragment key={id}>
          <span>Street: {address.street}</span>
          <span>City: {address.city}</span>
          <span>Lat: {address.geo.lat}</span>
          <span>Lng: {address.geo.lng}</span>
        </React.Fragment>
      );
    })}

If you really want to do it using a loop or some form of iteration you can look into Object.entries. But it would be really difficult to do that with nested objects if you do not know what you are dealing with.

contacts.map(({ address }) => {
  for (let [key, value] of Object.entries(address)) {
    console.log(`${key}: ${value}`); // logs "street: Kulas Light"
  }
})

but note for geo it will give "geo: [Object object]" if you put this directly into a span.

P.S I would recommend finding a better key than the index of array for the Fragment.

Related