'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

https://react-5maykf.stackblitz.io/



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