React-google-maps: Is there a better way to display InfoWindow?

Created on 7 Sep 2016  ·  6Comments  ·  Source: tomchentw/react-google-maps

looking at this example and a few things occur to me:

  • the mechanism for showing the window seems like an anti-pattern. it skips entirely the React management of state and props and just mutates an internal variable. is there a more 'react-y' pattern for this?
  • i use Immutable.js and pass my marker locations down through props. obviously i can't mutate props, so according to the pattern in the example, I should create an intermediate array of markers between props and render()? This seems really counter intuitive
  • Because it's instantiating an InfoWindow with each marker, there's potential to have dozens of instances of the element at any one time. again this seems far less efficient than the normal way (ie, render 1 InfoWindow, and dynamically tell it where to open)

I was looking at instead using a Popover from the MUI library, but that requires a DOM Element to determine the location it should open at

I'm also looking at the Google Maps API, and it looks like you can pass InfoWindow map coordinates. this would work great, but how do I pass that info to InfoWindow?

Most helpful comment

Hi @brandonmp, thank you for your example! I was able to use it and got my map to only show one InfoWindow at a time now.

I do have the issue you mention about the InfowWindow being exactly on top of the Marker and I'm struggling to figure out how to use the pixelOffset with this library.

screen shot 2017-03-19 at 11 32 22 am

I've imported the following at the top of my file:

import { InfoWindow } from 'react-google-maps';

and I've tried to add the options like this:

<InfoWindow 
        defaultPosition={ this.props.position }
        user={ this.props.user }
        options={{pixelOffset: new google.maps.Size(0,-30)}}
        mapHolderRef={ this.props.mapHolderRef } >
   { ... my content }
</InfoWindow> 

but I don't have access to google and can't figure out how to access the Size class as per Google's docs. I've also tried importing google-maps directly but that didn't work. I think probably because I use the react-google-maps library everywhere else. How did you get access to the Size class? I can't see it as part of this library?

Feeling a bit stumped and any help would be very appreciated!

@alengel
I am very new to React and I am also struggling to comprehend the 'loose' documentation that accompanies the majority of various unofficial React Google Maps libraries that are available.

I have a load of markers on my map, which I also only wanted one info window to open at a time. To avoid multiple info windows, I decided not to have them as children of every marker; Rather a single <InfoWindow> as a sibling of <Marker> & child of <GoogleMap>. When a <Marker> is clicked, it's lat, lng is then made stateful & used to position the <InfoWindow>.

As my <InfoWindow> is a separate component I have to introduce an offset so that it doesn't open directly above it's <Marker>. Through A LOT of trial and error I have come to the conclusion that anything that would usually require 'google.map' needs 'window' declared before hand. So for example

` animation={window.google.maps.Animation.DROP}

`

Therefore to achieve the offset on an <InfoWindow> try:

` options={{pixelOffset: new window.google.maps.Size(0,-40)}}

`

I know this solution address's a now very old query, but I do hope that this will help someone else in future and save a lot of time!

All 6 comments

After some messing around with it I arrived at this solution which I think will be more performant than the example.

if the devs agree that this is better i can submit a pr for a new example

a method in my map component:

InfoWindow can open at a specific coordinate, so we'll use the coordinate of the clicked marker.

First we control the visibility of the InfoWindow by placing its location in state, then write a toggle method. Basically, if windowPosition == null, window is closed, else windowPosition == {lat, lng}

 toggleInfoWindow = (loc) => {
    // clicking 'x' in the info window will pass null, so if we detect that, reset the position in state
    if (loc == null) {
      this.setState({ windowPosition: null })
      return
    }
    // otherwise get coords of clicked marker and set to state
    let markerLoc = { lat: loc.latLng.lat(), lng: loc.latLng.lng() }
    this.setState({ windowPosition: markerLoc })
  }

then inside our GoogleMap component, we create an <InfoWindow> component:

 <InfoWindow
                  position={this.state.windowPosition}
                  onCloseclick={this.toggleInfoWindow}
                  options={{pixelOffset: new google.maps.Size(0,-30)}}
                  >
  content
</InfoWindow>

note the options prop. because the InfoWindow is opened @ same point as our marker, if we don't offset it, it will cover the marker and look bad. this option moves the infoWindow up 30 pixels.

Lastly, in our Marker component, call the toggle method onClick:

<Marker
{...props}
onClick={this.toggleInfoWindow}
/>

@brandonmp <InfoWindow> can of course rendered separated without <Marker>. Yes an position props could do that!

Also, 6.0.0 is released on npm beta tag now. We also have a new demo page. Feel free to try it:
https://tomchentw.github.io/react-google-maps/

Hi @brandonmp, thank you for your example! I was able to use it and got my map to only show one InfoWindow at a time now.

I do have the issue you mention about the InfowWindow being exactly on top of the Marker and I'm struggling to figure out how to use the pixelOffset with this library.

screen shot 2017-03-19 at 11 32 22 am

I've imported the following at the top of my file:

import { InfoWindow } from 'react-google-maps';

and I've tried to add the options like this:

<InfoWindow 
        defaultPosition={ this.props.position }
        user={ this.props.user }
        options={{pixelOffset: new google.maps.Size(0,-30)}}
        mapHolderRef={ this.props.mapHolderRef } >
   { ... my content }
</InfoWindow> 

but I don't have access to google and can't figure out how to access the Size class as per Google's docs. I've also tried importing google-maps directly but that didn't work. I think probably because I use the react-google-maps library everywhere else. How did you get access to the Size class? I can't see it as part of this library?

Feeling a bit stumped and any help would be very appreciated!

Try use onClick inside html code , it work for me :dancer:

<InfoWindow  onCloseClick={props.onToggleOpen}>
            <div onClick={()=>{alert('hello')}} class="wow slideInLeft">
              <img src="https://i.imgur.com/7IgBxnH.jpg" width="150px" />
              <div>nhà trọ cho thuê</div>
              <div>1.500.000đ</div>
            </div>
</InfoWindow>

Hi @brandonmp, thank you for your example! I was able to use it and got my map to only show one InfoWindow at a time now.

I do have the issue you mention about the InfowWindow being exactly on top of the Marker and I'm struggling to figure out how to use the pixelOffset with this library.

screen shot 2017-03-19 at 11 32 22 am

I've imported the following at the top of my file:

import { InfoWindow } from 'react-google-maps';

and I've tried to add the options like this:

<InfoWindow 
        defaultPosition={ this.props.position }
        user={ this.props.user }
        options={{pixelOffset: new google.maps.Size(0,-30)}}
        mapHolderRef={ this.props.mapHolderRef } >
   { ... my content }
</InfoWindow> 

but I don't have access to google and can't figure out how to access the Size class as per Google's docs. I've also tried importing google-maps directly but that didn't work. I think probably because I use the react-google-maps library everywhere else. How did you get access to the Size class? I can't see it as part of this library?

Feeling a bit stumped and any help would be very appreciated!

@alengel
I am very new to React and I am also struggling to comprehend the 'loose' documentation that accompanies the majority of various unofficial React Google Maps libraries that are available.

I have a load of markers on my map, which I also only wanted one info window to open at a time. To avoid multiple info windows, I decided not to have them as children of every marker; Rather a single <InfoWindow> as a sibling of <Marker> & child of <GoogleMap>. When a <Marker> is clicked, it's lat, lng is then made stateful & used to position the <InfoWindow>.

As my <InfoWindow> is a separate component I have to introduce an offset so that it doesn't open directly above it's <Marker>. Through A LOT of trial and error I have come to the conclusion that anything that would usually require 'google.map' needs 'window' declared before hand. So for example

` animation={window.google.maps.Animation.DROP}

`

Therefore to achieve the offset on an <InfoWindow> try:

` options={{pixelOffset: new window.google.maps.Size(0,-40)}}

`

I know this solution address's a now very old query, but I do hope that this will help someone else in future and save a lot of time!

@cfdesign Thank you tremendously. I also encountered the 'google' not defined problem, and your answer saved me!

Was this page helpful?
0 / 5 - 0 ratings