react-leaflet seems to cause duplicate render calls with React18

323 Views Asked by At

The other day I updated my application to React18 and found that something has changed there in the behavior of react-leaflet. In my project I wrote a custom wrapper for the leaflet-geocoder, which is then used in the MapContainer

Geocoder:

export const Geocoder: FC<{}> = props => {

    //#region --Constants--
    const map: L.Map = useMap();
    const {t, i18n} = useTranslation();
    //#endregion

    //#region --States--


    //#endregion

    //#region --Hooks--
    useEffect(() => {

        Initialize();

    }, []);

    //#endregion

    //#region --Functions--

    const Initialize = (): void => {

        const controller: MapController = new MapController();

        const geocoderControl: GeocoderControl = geocoder({
            geocoder: geocoders.mapbox({
                apiKey: controller.Token,
                geocodingQueryParams: {
                    language: i18n.language
                }

            }),
            defaultMarkGeocode: false,
            placeholder: t("search"),
            errorMessage: t("noResult")
        });

        geocoderControl.on("markgeocode", result => {

            const codingResult: GeocodingResult = result.geocode ?? result;

            map.fitBounds(codingResult.bbox);

            const newPopup: L.Popup = popup()
                .setLatLng(codingResult.bbox.getCenter())
                .setContent(codingResult.html ?? codingResult.name)
                .openOn(map);


        });

        geocoderControl.addTo(map);


    };

    //#endregiony

    //#region --Render--

    return null;

    //#endregion

};

Usage in the MapContainer of React-Leaflet:

<MapContainer center={props.latLng ?? defaultPosition} zoom={13} scrollWheelZoom={true}>
                <TileLayer
                    attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                    url={mapController.BaseUrl}
                    accessToken={mapController.Token}
                    id={eLayer.STREETS}
                />
                {
                    props.enableGeoCoding ?
                        <Geocoder/>
                        : null
                }
                <Markers latLng={props.latLng} fieldSetter={props.fieldSetter}/>
            </MapContainer>

With the 17 version of React, it all worked and gave the following result: Map with one geocoder

Which is correct, the map shows only one geocoder. But now in React18 it looks like this: two geocoders

After that I created a profile with the react-devtools and looked there why this renders again, the result was that the useMap() hook inside the GeoCoder wrapper seems to change.

Do you know why this hook seems to change since the 18 version, code-wise nothing has changed in my code between React17 and 18.

1

There are 1 best solutions below

0
On BEST ANSWER

This can be fixed by saving a reference to the geocoder, and deleting the control from the map when cleaning up the hook