react-mapbox-gl icon indicating copy to clipboard operation
react-mapbox-gl copied to clipboard

fillOnMouseLeave doesn't get called

Open n23daniel opened this issue 6 years ago • 9 comments

I'm using a <GEOJSONLayer/> to display some polygons. I'm using a combo of mousemove and mouseleave to display a popup of the current polygon:

<GeoJSONLayer
  data={polygons}
  fillPaint={{
    'fill-color': '#333',
    'fill-opacity': 0.1,
  }}
  fillOnMouseMove={e => {
    console.log('MOUSE MOVE', e)
    if (!currentPolygon || currentNeighbourhoodHover.properties.id !== e.features[0].properties.id) {
      this.setState({
        currentPolygon: e.features[0]
      })
    }
  }}
  fillOnMouseLeave={e => {
    console.log('MOUSE LEAVE', e)
    this.setState({
      currentPolygon: null,
    })
  }}
  />

My problem is that fillOnMouseLeave event gets called only like 3/4 of time, and so I can't hide the popup displayed. It mostly relates to the speed the mouse is moving.

Previously, everything worked fine with the non react mapboxgl-js library like map.on('mouseleave', 'polygons-layer', mouseLeaveListener), so I'm guessing the problem is not from the core library.

n23daniel avatar Jan 26 '18 17:01 n23daniel

+1 I'm also getting this issue

glorp47 avatar Jan 31 '18 21:01 glorp47

+1

w3z315 avatar Feb 02 '18 09:02 w3z315

+1 Same thing with circleOnMouseLeave, does work only if no circleOnMouseEnter function is set. However, it works well if there is no call to setState inside the OnMouseEnter callback.

kaligrafy avatar Oct 25 '18 17:10 kaligrafy

Any update on this?

glorp47 avatar Dec 04 '18 20:12 glorp47

Move your event handlers outside the render function so they won't be recreated each time render when state changes. This fixed this for me.

Event re-registration code looks okay at first glance - https://github.com/alex3165/react-mapbox-gl/blob/master/src/geojson-layer.ts#L317, so maybe the leave event handler fires somewhere in between off and on...

msokk avatar Dec 29 '18 13:12 msokk

any update on this, or workaround?

I can get the fillOnMouseLeave function to trigger when I only use leave/enter, but if I use fillOnMouseMove the leave function never triggers.

Makes it difficult to remove e.g. a tooltip when the mouse leaves the GeoJSON...

linden-dg avatar May 25 '20 10:05 linden-dg

If anyone else is having this issue and using functional components/hooks, wrapping the fillOnMouseLeave in a callback seems to fix it.

e.g. something like:


const Map = ( ) => {
  const memoizedMouseLeave = useCallback(() => {
    //do something on mouse leave
  }, []);
  const onHover = e => {
    //do something on hover
  };

  return (

      <MapGL>
        <GeoJSONLayer
          fillOnMouseLeave={memoizedMouseLeave}
          fillOnMouseEnter={onHover}
        />
      </MapGL>

  );
};

linden-dg avatar May 25 '20 11:05 linden-dg

I was able to get fillOnMouseLeave to work by binding the functions in the constructor instead of one-lining it like the example does. I'm not sure why it works like this.

  constructor(props) {

        super(props)

        this.state = {
            county: 'county name',
            center: {
                lng: -71.77,
                lat: 43.71
            },
            zoom: [6]
        }

        this.onClickFill = this.onClickFill.bind(this);
        this.onEnter = this.onEnter.bind(this)
        this.onExit = this.onExit.bind(this)
    }

  render() {

        return (

              <GeoJSONLayer
                    data={this.getGeojson()}
                    fillPaint={this.fillStyle()}
                    before='waterway-label'
                    fillOnClick={this.onClickFill}
                    fillOnMouseEnter={this.onEnter}
                    fillOnMouseLeave={this.onExit}
                    // not like this: fillOnMouseLeave={this.onExit.bind(this, 'grab')}

                        />

)
}

sebastian-ch avatar Jun 06 '20 08:06 sebastian-ch

I'm in a functional component. If I try to useCallback(,[something]) with something in the dependency array, then fillOnMouseLeave does not work. I got around this by setting up const [leaveEvent, setLeaveEvent] = useState() and setting fillOnMouseLeave={setLeaveEvent} then putting my "real" handler in an effect like useEffect(()={}, [leaveEvent]) that runs when there is a new leaveEvent.

jbeuckm avatar Sep 22 '21 20:09 jbeuckm