I'm using Locate Control in React Leaflet, but the Locate Control buttons are always duplicated, and sometimes I get 3 or 4 of them (see image below). I'm running the function through a useEffect with empty dependency to only fire it once, but no matter. I can target the class with display: none, but then both disappear. I feel like this might be an issue with Locate Control library? Really not sure. Open to any help or ideas.
import { useEffect } from "react"
import { useMap } from "react-leaflet"
import Locate from "leaflet.locatecontrol"
import "leaflet.locatecontrol/dist/L.Control.Locate.min.css"
const AddLocate = () => {
const map = useMap()
useEffect(() => {
const locateOptions = {
position: "bottomleft",
flyTo: true,
}
const locateControl = new Locate(locateOptions)
locateControl.addTo(map)
}, [])
return null
}
export default AddLocate;
CodePudding user response:
I would do some debugging to that useEffect to see if it's only happening once. It's possible the entire component is mounted multiple times.
CodePudding user response:
Looks like you use a package made for leaflet. Which should for the most parts be okay. However the way you add the control is not really the react-leaflet
way, where we want to add add components rather than add "stuff" directly to the map.
Below you can see how easy it is to implement a location component that you simply just can add as component within your MapContainer.
import { ActionIcon } from "@mantine/core";
import React, { useState } from "react";
import { useMapEvents } from "react-leaflet";
import { CurrentLocation } from "tabler-icons-react";
import LeafletControl from "./LeafletControl";
interface LeafletMyPositionProps {
zoom?: number;
}
const LeafletMyPosition: React.FC<LeafletMyPositionProps> = ({ zoom = 17 }) => {
const [loading, setLoading] = useState<boolean>(false);
const map = useMapEvents({
locationfound(e) {
map.flyTo(e.latlng, zoom);
setLoading(false);
},
});
return (
<LeafletControl position={"bottomright"}>
<ActionIcon
onClick={() => {
setLoading(true);
map.locate();
}}
loading={loading}
variant={"transparent"}
>
<CurrentLocation />
</ActionIcon>
</LeafletControl>
);
};
export default LeafletMyPosition;
And for LeafletControl I just have this reusable component:
import L from "leaflet";
import React, { useEffect, useRef } from "react";
const ControlClasses = {
bottomleft: "leaflet-bottom leaflet-left",
bottomright: "leaflet-bottom leaflet-right",
topleft: "leaflet-top leaflet-left",
topright: "leaflet-top leaflet-right",
};
type ControlPosition = keyof typeof ControlClasses;
export interface LeafLetControlProps {
position?: ControlPosition;
children?: React.ReactNode;
}
const LeafletControl: React.FC<LeafLetControlProps> = ({
position,
children,
}) => {
const divRef = useRef(null);
useEffect(() => {
if (divRef.current) {
L.DomEvent.disableClickPropagation(divRef.current);
L.DomEvent.disableScrollPropagation(divRef.current);
}
});
return (
<div ref={divRef} className={position && ControlClasses[position]}>
<div className={"leaflet-control"}>{children}</div>
</div>
);
};
export default LeafletControl;