1

I'm experimenting with React, and I want to render a few markers on a map (I'm using Google Maps API). Now, everything is fine if I hardcode the markers (in the example, 5 markers, each with different coordinates, name and description, as in the locations array below). But what if i want to loop through the array and render them without hardcoding at all? I defined the renderMarkers function before the render(). Any help would be appreciated. Thanks!

/* Main component state */
state = {
    showingInfoWindow: false,
    activeMarker: {},
    selectedPlace: {},
    mapReady: true,
    desc: '',
    animation: null,
    locations: 
  [
   {
    "locationName": "name1",
    "position": '{"lat": "lat1", "lng": "lng1"}',
    "desc": "desc1"
  },
  {
    "locationName": "name2",
    "position": '{"lat": "lat2", "lng": "lng2"}',
    "desc": "desc2"
  },
  {
    "locationName": "name3",
    "position": '{"lat": "lat3", "lng": "lng3"}',
    "desc": "desc3"
  },
  {
    "locationName": "name4",
    "position": '{"lat": "lat4", "lng": "lng4"}',
    "desc": "desc4."
  },
  {
    "locationName": "name5",
    "position": '{"lat": "lat5, "lng": "lng5"}',
    "desc": "desc5."
  }
 ]
};

/* Function to render the markers, each with their relevant info taken from the state.locations array, on the map */
renderMarkers = () => {
for (let i = 0; i < this.state.locations.length; i++) {
  return <Marker
      onClick = { this.onMarkerClick }
      title = { this.state.locations[i].locName }
      position = { JSON.parse(this.state.locations[i].position) }
      desc = { this.state.locations[i].desc }
      animation = { this.state.animation[i] }
      name = { this.state.locations[i].locName } />
   }
 }
Bruno Mazza
  • 675
  • 1
  • 10
  • 24
  • 1
    Use the map() function to map over the array inside render(), this structure will make it rerender when the locations array is updated. – A. Larsson Jul 31 '18 at 11:32
  • Thanks for the reply, @A.Larsson. As I'm super new to this, is it ok to declare inside of the render() function? [Here](https://stackoverflow.com/questions/41369296/react-functions-inside-render) says it's better not. What if I declare in the class, and then invoke it inside of the return using {}? – Bruno Mazza Jul 31 '18 at 12:48

1 Answers1

3
  1. Use map function to create an array of Markers.
  2. renderMarkers function should be put outside of the render function. Otherwise renderMarkers will be recreated each time the component's state is changed, because render is invoked on each state change (performance hit).

renderMarkers() {
  return this.state.locations.map((location, i) => {
    return <Marker
      key={ i }
      onClick = { this.onMarkerClick }
      title = { location.locName }
      position = { JSON.parse(location.position) }
      desc = { location.desc }
      animation = { this.state.animation[i] }
      name = { location.locName } />
  })
}

render() {
  return <div>{ this.renderMarkers() }</div>
}
A. Larsson
  • 1,319
  • 11
  • 16
Jordan Enev
  • 16,904
  • 3
  • 42
  • 67
  • Hi @jordan, thanks for the answer. I tried following your approach, which makes a lot of sense, but I get an "TypeError: Cannot read property '0' of null" related to `animation = { this.state.animation[i] }`. I saved the whole component code on this [bin](https://jsbin.com/huwocah/edit?html,js,output), if you wanted to help me fix this. Thanks a lot! – Bruno Mazza Jul 31 '18 at 14:07
  • It's because the animation is `null`. As I'm seeing you use the same animation for all the markers. So you can pass it as follow: `animation = { this.props.google.maps.Animation.DROP }` and it should work. Also the question is related to rendering an array of markers, so if my answer helps you - you can accept it. Thanks. – Jordan Enev Jul 31 '18 at 14:19
  • Glad I helped you! – Jordan Enev Jul 31 '18 at 14:32