Amruth
Amruth

Reputation: 13

How to return multiple components for each element in a array using map()?

I tried to do it in this way. I want to return multiple <LocationMarker> for each "ev". But it's only returning one <LocationMarker> for each "ev". for loop inside the storm variable is only executing once. I also tried keeping for loop inside the return function but got an error.

Thanks in Advance

import { useState } from 'react';
import GoogleMapReact from 'google-map-react';
import LocationMarker from './LocationMarker';
import LocationInfoBox from './LocationInfoBox';
const NATURAL_EVENT_SEVERESTORMS = 'severeStorms';
const Map = ({ eventData, center, zoom }) => {
const [locationInfo, setLocationInfo] = useState(null);
const storms = eventData.map((ev) => {
    if (ev.categories[0].id === NATURAL_EVENT_SEVERESTORMS) {
      for (let i = 0; i < ev.geometry.length; i++) {
        return (
          <LocationMarker
            lat={ev.geometry[i].coordinates[1]}
            lng={ev.geometry[i].coordinates[0]}
            type='severeStorms'
            onClick={() => setLocationInfo({ id: ev.id, title: ev.title })}
          />
        );
      }
    }
    return null;
  });

  return (
    <div className='map'>
      <GoogleMapReact
        bootstrapURLKeys={{  }}
        defaultCenter={center}
        defaultZoom={zoom}
      >
        {storms}
      </GoogleMapReact>

      {locationInfo && <LocationInfoBox info={locationInfo} />}
    </div>
  );
};

Map.defaultProps = {
  center: {
    lat: 42.3265,
    lng: -122.8756,
  },
  zoom: 4,
};

export default Map;


Upvotes: 1

Views: 1929

Answers (3)

Kanhaiya Mishra
Kanhaiya Mishra

Reputation: 53

You will have to add all LocationMarker in an array, and then return the array,

What you are doing now, is traversing the loop, and then on first index (i=0), returning the

<LocationMarker
        lat={ev.geometry[i].coordinates[1]}
        lng={ev.geometry[i].coordinates[0]}
        type='severeStorms'
        onClick={() => setLocationInfo({ id: ev.id, title: ev.title })}
      />

from storms function.

Upvotes: 0

Goran.it
Goran.it

Reputation: 6299

You have two nested loops there, so in order to get the actual array you need to concatenate each loop record, or just use reduce. Something like this should work:

import { useState } from 'react';
import GoogleMapReact from 'google-map-react';
import LocationMarker from './LocationMarker';
import LocationInfoBox from './LocationInfoBox';
const NATURAL_EVENT_SEVERESTORMS = 'severeStorms';
const Map = ({ eventData, center, zoom }) => {
const [locationInfo, setLocationInfo] = useState(null);
const storms = eventData.reduce((acc, ev, indx) => {
  const geometries = ev.geometry.map((geo, geoIndx) => (
      <LocationMarker
        key={`${indx}-${geoIndx}`}
        lat={geo.coordinates[1]}
        lng={geo.coordinates[0]}
        type='severeStorms'
        onClick={() => setLocationInfo({ id: ev.id, title: ev.title })}
      />
  )
  // Concatenate previously collected records with this iteration map output
  acc = acc.concat(geometries)
  return acc
}, [])


  return (
    <div className='map'>
      <GoogleMapReact
        bootstrapURLKeys={{  }}
        defaultCenter={center}
        defaultZoom={zoom}
      >
        {storms}
      </GoogleMapReact>

      {locationInfo && <LocationInfoBox info={locationInfo} />}
    </div>
  );
};

Map.defaultProps = {
  center: {
    lat: 42.3265,
    lng: -122.8756,
  },
  zoom: 4,
};

export default Map;

Upvotes: 0

Ron Rofe
Ron Rofe

Reputation: 796

You are returning the LocationMarker JSX in the first iteration of the for loop. Instead of it, you should use the map method again.

const storms = eventData.map((ev) => {
  if (ev.categories[0].id === NATURAL_EVENT_SEVERESTORMS) {
    return ev.geometry.map((geo) => {
      return (
        <LocationMarker
          lat={geo.coordinates[1]}
          lng={geo.coordinates[0]}
          type='severeStorms'
          onClick={() => setLocationInfo({ id: ev.id, title: ev.title })}
        />
      );
    });
  }
  return null;
});

Also note that you have to add a 'key' property when iterating to render JSX list.

const storms = eventData.map((ev) => {
  if (ev.categories[0].id === NATURAL_EVENT_SEVERESTORMS) {
    return ev.geometry.map((geo) => {
      return (
        <LocationMarker
          key={CHOOSE_UNIQUE_KEY_FOR_THIS_ITEM}
          lat={geo.coordinates[1]}
          lng={geo.coordinates[0]}
          type='severeStorms'
          onClick={() => setLocationInfo({ id: ev.id, title: ev.title })}
        />
      );
    });
  }
  return null;
});

You can read more about this here: https://reactjs.org/docs/lists-and-keys.html

Upvotes: 1

Related Questions