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
.