Search code examples
react-google-maps

react-google-maps multiple markers breaks on open


My app loads all my markers just fine, but crashes when I try and click a marker. I get the following error: "React.Children.only expected to receive a single React element child."

In the main map component I build the map and bring in all the markers from Firebase. I wanted to componentize the markers and build them in a separate file just to keep things a bit straighter in my head.

Here is my Map component

const MyMapComponent = compose(
withProps({
    googleMapURL: "https://maps.googleapis.com/maps/api/js?key=xxxxx&v=3.exp&libraries=geometry,drawing,places",
    loadingElement: <div style={{ height: `100%` }} />,
    containerElement: <div style={{ height: `500px` }} />,
    mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
    defaultZoom={15}
    defaultCenter={{ lat: 34.6781445, lng: -82.8455519 }}
>
    {props.markers.map(marker => (
        <LotMarker key={marker.key} index={marker.key} lat={marker.latitude} lng={marker.longitude} />
    ))}
</GoogleMap>
);

class TheMap extends React.PureComponent {

    constructor(props) {
        super(props);
        this.state = {
            test:'test',
            lots: [],
            isOpen: false
        };
    }

    componentWillMount() {
        base.bindToState('lots', {
            context: this,
            state: 'lots',
            asArray: true,
        });
    }

    handleMarkerClick = (key) => {
        console.log(key);
    }

    render() {
        return (
            <MyMapComponent
            isMarkerShown={this.state.isMarkerShown}
            onMarkerClick={this.handleMarkerClick} 
            markers={this.state.lots} 
            />
        )
    }
}
export default TheMap;

Here I put the marker together. I've housed the InfoWindow component inside the marker and then ask it to show when the marker is clicked. However, when I do click a marker it just crashes the whole app and white screens.

This is my LotMarker component:

class LotMarker extends React.Component {

// Constructor.
constructor(props) {
    // Super Props.
    super(props);
    // State.
    this.state = {
        isOpen: false
    }
}

onToggleOpen = () => {
    console.log(this);
    this.setState({isOpen: !this.state.isOpen});
}


// Render.
render() {

// console.log(this);

    // Extract Props.
    const {
        props: {
            index,
            lat,
            lng,
            open
        }
    } = this

return (
    <Marker key={index} position={{ lat: lat, lng: lng }} onClick={this.onToggleOpen}>
        {this.state.isOpen && <InfoWindow onCloseClick={this.onToggleOpen}>{index}</InfoWindow>}
    </Marker>
    )
}
}

export default LotMarker;

Solution

  • Alright, it turns out there was a really simple fix here. The content inside the InfoWindow has to be wrapped in a JSX compliant element.

    Rather than this:

    <InfoWindow onCloseClick={this.onToggleOpen}>{index}</InfoWindow>
    

    I had to have this:

    <InfoWindow onCloseClick={this.onToggleOpen}><span>{index}</span></InfoWindow>