adamoe
adamoe

Reputation: 23

I get 'There is already a source with this ID' at initial Effect- mapbox gl js

Im trying to implement a custom DrawControl with mapbox-gl-js with Next 14 In the Dev Enviroment im using React Strict Mode so my useEffect's render twice.

Now i want to create the Control with the Mapbox useControl hook. After i've set my useRef with the new Control i want to add the Control to the map (without this step i get multiple errors, when trying to use the control with its functions)

After that i want to add a array of features to my custom DrawControl. I've a custom logic for the draw Control.

And its working. The Items get added but then im in a infinite loop with the errormessage There is already a source with this ID. so theirfore there is an error, because "mapRef.current.addControl(drawControl) gets called multiple times. But why? :(

My useEffect dep arrays are emty theirfore it should run only twice (strict mode) otherwise once

Thanks your ur help I wasted 8h at this problem :)

import MapboxDraw from '@mapbox/mapbox-gl-draw';
import { useCallback, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { useControl, useMap } from 'react-map-gl';
import * as MapboxDrawWaypoint from './utils/custom-prevent-control';
import DrawControl from './draw-control';

export default function DrawControlContainer({ container = {}, child = {} }) {
  const { onCreate, onUpdate, onDelete, onActive, clearChangeRange } = container;
  const { initialData = [] } = child;

  const mapRef = useMap();
  const drawRef = useRef(null);

  // Custom Draw behaviour
  let { modes } = MapboxDraw;
  modes = MapboxDrawWaypoint.enable(modes);
  // ----

  useControl(
    () => {
      const draw = new MapboxDraw({
        modes,
        displayControlsDefault: false,
        controls: {
          polygon: true,
          trash: true,
        },
      });

      drawRef.current = draw;
      return draw;
    },
    () => {

      mapRef.current.on('draw.create', (e) => {
        onCreate(e.features[0]);
      });

      mapRef.current.on('draw.update', (e) => {
        onUpdate(e.features[0]);
      });

      mapRef.current.on('draw.delete', (e) => {
        // Hier muss noch ein Confirm eingebaut werden.
        onDelete(e.features.map((feature) => feature.id));
      });

      mapRef.current.on('draw.selectionchange', (e) => {
        const activeFeature = e.features[0];

        if (activeFeature) {
          onActive(activeFeature?.id);
        } else {
          onActive('');
          clearChangeRange();
        }
      });
    },
    () => {
      // Cleanup method, if needed
    },
    { position: "top-left" }
  )

  const initItems = useCallback(() => {
    mapRef.current.addControl(drawRef.current);

    initialData.forEach(item => {
      drawRef.current.add(item);
    });
    // eslint-disable-next-line
  }, [])

  useEffect(() => {
    initItems();
    // eslint-disable-next-line
  }, [])

  return drawRef.current ? <DrawControl drawRef={drawRef} {...child} /> : null;
}

DrawControlContainer.propTypes = {
  container: PropTypes.object,
  child: PropTypes.object
}

I tried multiple types of Refs and States, multiple useEffects.

I created the control manually and with the useControl hook from mapbox but it's not working :(

Upvotes: 0

Views: 45

Answers (0)

Related Questions