'How to disable an event listener in mapbox?
I am trying to have control over event listeners over a layer with Mapbox on React. map.off is supossed to do the trick, but it is not removing the onclick event in a layer. https://docs.mapbox.com/mapbox-gl-js/api/map/#map#off
But I am doing something wrong so I can't manage to remove the event. Here is what I have done so far...
To add the event I do this
map.on('click', 'building_footprints_click', addBuildingPopUp)
And to try to remove it I tried:
map.off('click', 'building_footprints_click', addBuildingPopUp);
map.off('click', 'building_footprints_click');
map.off('click', addBuildingPopUp);
But none of them are working. I read that I have to send to off the instance of the on event. So I tried to:
let event = map.on('click', 'building_footprints_click', addBuildingPopUp)
and the same three off operations as above but they don't work either
map.off('click', 'building_footprints_click', event);
map.off('click', 'building_footprints_click');
map.off('click', event);
And also the listener function, I have tried with:
const addBuildingPopUp = (e) => {}
and
function addBuildingPopUp (e) {}
and
let addBuildingPopUp = function building (e) {}
Here is a basic Stackblitz with a example of the non working function https://stackblitz.com/edit/react-5maykf?file=src/App.js
Solution 1:[1]
Based on your stackblitz I can see that the problem is that you are trying to deregister a function that no longer exists.
For mapbox you need to register and deregister the same function. I mean
map.on('mousemove', f1)
and map.off('mousemove', f1)
you need to ensure that f1 remains the same.
Let me explain that, whenever a react component renders, it does recreate all variables inside it's body unless it is part of a state variable, since the function addBuildingPopUp
is created on every render mapboxgl does not deregister the event.
The only change you need to do is to ensure addBuildingPopUp
remains the same, you should define outside React Component.
Solution 2:[2]
I checked your stackblitz code and update the working answer accordingly with comments. Let me know if you have any questions on it
https://stackblitz.com/edit/react-mqjjkg?devtoolsheight=33&file=src/App.js
Solution 3:[3]
If you use React, just store the handler(s) inside of useRef, and voila, everything will work, here's the similar situation and a proposed solution
Here's the code for the solution:
const handleClickRef = useRef(handleClick)
handleClickRef.current = handleClick
map.on('mousedown', 'layer-id', handleClickRef.current)
map.off('mousedown', 'layer-id', handleClickRef.current)
Solution 4:[4]
The Functions that you pass to the mapbox event Listener have to be exactly the same. Everytime a component renders in react, the function (although it stays the same) will be recognized by javascript as a new declared function. Therefore mapbox will "off" a listener, that doesn't event exist, because it's a function thats never been there. To solve it, you have to use React "useCallback". It ensures that functions remain the same over the course of the existence of the component
export default function MapListeners() {
const mode = useRecoilValue(interactivityMode);
const setModal = useSetRecoilState(modalState);
const removeListeners = () => {
cuMap.off("click", setAddBeaconModal);
};
const setAddBeaconModal = useCallback(
// useCallback ensures the functions stays identical
(e: mapboxgl.MapMouseEvent & mapboxgl.EventData) => {
// const coordinates = e.lngLat;
setModal({
key: AddBeaconModal.toString(),
body: {
component: AddBeaconModal,
props: { word: "irgendwas", title: "Irrr" },
},
title: "Add Beacon",
});
},
[]
);
const setMapListeners = () => {
removeListeners();
switch (mode) {
case "add":
cuMap.on("click", setAddBeaconModal);
break;
case "lock":
break;
default:
}
};
useEffect(setMapListeners, [mode]);
return null;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | pachonjcl |
Solution 2 | Dolly |
Solution 3 | Alexandr Bich |
Solution 4 | Michael Payne |