5

I am trying to open a infowindow on a specific marker on click, however when i click one it appears that all of them are opening instead, and showing me this error: React.Children.only expected to receive a single React element child.

This is what my code looks like right now:

import React, { Component } from 'react';
import {  GoogleMap, Marker, withGoogleMap, withScriptjs, InfoWindow } from 'react-google-maps'

class Map extends Component {
  state = {
    isOpen: false
  }

  handleMarkerClick = () => {
    this.setState({ isOpen: true})
  }

  render() {
    return(
    <div>
      <GoogleMap
        defaultZoom={13}
        defaultCenter={{ lat: -22.9034778, lng: -43.1264636 }}
      >{this.props.markers.map((marker, index) =>(
        <Marker
          key={index}
          position={marker.location}
          onClick={this.handleMarkerClick}
         >{this.state.isOpen && <InfoWindow onCloseClick={this.handleMarkerClick}/>}
       </Marker>
      ))}
      </GoogleMap>
    </div>
    )
  }
}

export default withScriptjs(withGoogleMap(Map))

Start of Edit

I made some changes to try and address the comment, however it isn't working yet, can you give me some hints on what i'm doing wrong, since i made some changes to the top component i will paste it here too:

import React, { Component } from 'react';
import Map from './Map.js'
import List from './List.js'
import escapeRegExp from 'escape-string-regexp'
import sortBy from 'sort-by'

class App extends Component {
  state ={
    locations:[
      {
        name: "Paróquia Nossa Senhora das Dores do Ingá",
        location: {
          lat: -22.9038875,
          lng: -43.1252873
        },
        isOpen:false,
      },
      {
        name: "Museu de Arte Contemporanea de Niteroi",
        location: {
          lat: -22.9078182,
          lng: -43.1262919
        },
        isOpen:false,
      },
      {
        name: "UFF - Faculdade de Direito",
        location: {
          lat: -22.9038469,
          lng: -43.126024
        },
        isOpen:false,
      },
      {
        name: "Ponte Rio-Niterói",
        location: {
          lat: -22.8701,
          lng: -43.167
        },
        isOpen:false,
      },
      {
        name: "Fundação Oscar Niemeyer",
        location: {
          lat: -22.888533927137285,
          lng: -43.12815992250511
        },
        isOpen:false,
      },
      {
        name: "Campo de São Bento",
        location: {
          lat: -22.905279,
          lng: -43.107759
        },
        isOpen:false,
      }
    ],
    query:''
  }

  onToggleOpen = (location) => {
    this.setState({ isOpen: !this.isOpen })
  }

  updateQuery = (query) => {
    this.setState({ query: query.trim() })
    console.log(query)
  }

  componentDidMount() {}
  render() {
    const { query, locations } = this.state

    let filteredMarkers
    if(query) {
      const match = new RegExp(escapeRegExp(query), 'i')
      filteredMarkers = locations.filter((location) => match.test(location.name))
    }else {
      filteredMarkers = locations
    }

    filteredMarkers.sort(sortBy('name'))

    return (
      <div className="App">
        <div style={{height:`5vh`}}>
          <input
            type='text'
            placeholder='Search locations'
            value={query}
            onChange={(event) => this.updateQuery(event.target.value)}
          />
        </div>
        <List
          markers={filteredMarkers}
        />
        <Map
          onToggle={this.onToggleOpen}
          googleMapURL="https://maps.googleapis.com/maps/api/js?&key=AIzaSyAiqO5W1p5FAFf8RZD11PGigUXSlmVHguQ&v=3"
          loadingElement={<div style={{ height: `100%` }} />}
          containerElement={<div style={{ height: `80vh` }} />}
          mapElement={<div style={{ height: `100%` }} />}
          className="Map"
          markers={filteredMarkers}
        />
      </div>
    );
  }
}

export default App;

Map.js

import React, { Component } from 'react';
import {  GoogleMap, Marker, withGoogleMap, withScriptjs, InfoWindow } from 'react-google-maps'

class Map extends Component {
  render() {
    return(
    <div>
      <GoogleMap
        defaultZoom={13}
        defaultCenter={{ lat: -22.9034778, lng: -43.1264636 }}
      >{this.props.markers.map((marker, index) =>(
        <Marker
          key={index}
          position={marker.location}
          onClick={() => this.props.onToggle(marker)}
         >{marker.isOpen && <InfoWindow onCloseClick={this.ontoggleOpen}>Hello</InfoWindow>}
       </Marker>
      ))}
      </GoogleMap>
    </div>
    )
  }
}

export default withScriptjs(withGoogleMap(Map))
Daniel Campos
  • 328
  • 2
  • 16
  • In your `Map` state you have a single property which you check and display an `InfoWindow` for all of info windows that you can have. Therefore, if you click on a single marker, all of the info windows will display. You should keep track of which Marker was clicked and then output info window for the marker with the same `index` – Anton Kastritskiy Dec 09 '17 at 21:33
  • Hey AntK i tried making some changes according to your comment, however i couldn't get it to work can you give me some help, i edited the post to show the changes. – Daniel Campos Dec 10 '17 at 14:00
  • can you share an example on what `props.markers` look like, this will help me make a working example – Anton Kastritskiy Dec 10 '17 at 14:07
  • The props.markers is the locations array that is in the state, this is one of the locations:{ name: "Paróquia Nossa Senhora das Dores do Ingá", location: { lat: -22.9038875, lng: -43.1252873 }, isOpen:false, } – Daniel Campos Dec 10 '17 at 14:17
  • I messed around a little more and noticed the click handler is working i just can't set the state with the onToggleOpen function, so i believe that is where the problem is. – Daniel Campos Dec 10 '17 at 17:38
  • you can also save in your map's component state the index of the marker for which you want to open the infoWindow and check if index of the market is same as the one that was clicked then output the infoWindow – Anton Kastritskiy Dec 10 '17 at 18:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/160882/discussion-between-daniel-campos-and-antk). – Daniel Campos Dec 10 '17 at 18:10

1 Answers1

15

The problem i was having with React.Children.only expected to receive a single React element child. was being caused because i didn't set a div inside the infowindow, so simply by adding it this particular problem was solved.

Here is what it used to look like:

<InfoWindow onCloseClick={this.handleMarkerClick}/>

here is what it should look like: <InfoWindow onCloseClick={()=>this.props.onToggle(marker)}><div>Hello</div></InfoWindow>

or something along these lines.

Daniel Campos
  • 328
  • 2
  • 16