react-mapbox-gl
react-mapbox-gl copied to clipboard
fillOnMouseLeave doesn't get called
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.
+1 I'm also getting this issue
+1
+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.
Any update on this?
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...
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...
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>
);
};
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')}
/>
)
}
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.