alex3165 / react-leaflet-draw

React component for leaflet-draw on top of react-leaflet
227 stars 151 forks source link

State reseted to initial state when creating shape ? #184

Closed HermanPierre closed 3 months ago

HermanPierre commented 3 months ago

Hello, I'm currently trying to use react leaflet draw on a NextJS typescript projet, and here is my draw map code :

'use client';

import { Feature } from 'geojson';
import * as L from 'leaflet';
import React, { useEffect, useState } from 'react';
import { FeatureGroup, MapContainer, TileLayer } from 'react-leaflet';
import { EditControl } from 'react-leaflet-draw';

import useUserStore from '@/store/userStore';

import 'leaflet/dist/leaflet.css';
import 'leaflet-draw/dist/leaflet.draw.css';

interface DrawToolProps {
    drawedPolygons: Feature[];
    setDrawedPolygons: (drawedPolygons: Feature[]) => void;
}

const DrawTool = ({ drawedPolygons, setDrawedPolygons }: DrawToolProps) => {
    // const map = useMap();
    const [featureGroup, setFeatureGroup] = useState<L.FeatureGroup | null>(null);

    useEffect(() => {
        console.log({ drawedPolygons });
    }, [drawedPolygons]);

    useEffect(() => {
        console.log({ featureGroup });
    }, [featureGroup]);

    const handleCreated = (e: L.DrawEvents.Created) => {
        const { layerType, layer } = e;
        console.log({ drawedPolygons, concat: drawedPolygons?.concat(layer.toGeoJSON()) });
        setDrawedPolygons(drawedPolygons?.concat(layer.toGeoJSON()));
        // if (layerType === 'polygon') {
        //     setPolygons([...polygons, layer.toGeoJSON()]);
        // } else if (layerType === 'polyline') {
        // const line = layer.toGeoJSON();
        // const newPolygons = polygons.flatMap((polygon) => {
        //     const cut = cutPolygonWithThickLine(polygon as Feature<Polygon, GeoJsonProperties>, line, 'cut_');
        //     console.log({ cut });
        //     return cut ? cut.features : [polygon];
        // });
        // setPolygons(newPolygons);
        // featureGroup?.clearLayers();
        // newPolygons.forEach((poly) => {
        //     L.geoJSON(poly).addTo(featureGroup as L.FeatureGroup);
        // });
        // }
    };

    return (
        <FeatureGroup ref={(fg) => setFeatureGroup(fg)}>
            <EditControl
                onCreated={handleCreated}
                draw={{
                    polyline: {
                        shapeOptions: {
                            color: '#000000',
                            fillColor: '#000000',
                        },
                    },
                    rectangle: false,
                    marker: false,
                    circlemarker: false,
                    polygon: {
                        allowIntersection: true,
                        showArea: true,
                        showLength: true,
                        // metric: ['ha'],
                        shapeOptions: {
                            color: 'lightgreen',
                            fillColor: 'lightgreen',
                        },
                    },
                    circle: false,
                }}
                position="topright"
            />
        </FeatureGroup>
    );
};

export default function DrawMap() {
    const user = useUserStore((state) => state.user);
    const [drawedPolygons, setDrawedPolygons] = useState<Feature[]>([]);

    return (
        <>
            <MapContainer
                key="draw-map"
                style={{ width: '100%', height: '100%' }}
                zoom={user?.zoom_agr || 13}
                center={[user?.lat_agr || 0, user?.lng_agr || 0]}
            >
                <TileLayer
                    attribution='&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors'
                    url="https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}"
                    maxZoom={20}
                    subdomains={['mt0', 'mt1', 'mt2', 'mt3']}
                />
                <DrawTool drawedPolygons={drawedPolygons} setDrawedPolygons={setDrawedPolygons} />
            </MapContainer>
        </>
    );
}

And everytime a new shape is created, it goes through the handleCreate function but the state "drawedPolygons" is always reseted to initial value, I tried importing it as a prop, using it as an element of a zustand store but everytime it magically becomes empty again.. Bu my featuregroup contains the multiples shape layers and they are also shown on the map. No useEffect is triggered when the state is back to inital I have no idea where this action is made... Thanks

HermanPierre commented 3 months ago

Okay I'm dumb, putting the code that works now here if it can help someone one day:

'use client';

import { Feature, GeoJsonProperties, Geometry } from 'geojson';
import * as L from 'leaflet';
import React, { useCallback, useEffect, useState } from 'react';
import { FeatureGroup, MapContainer, TileLayer } from 'react-leaflet';
import { EditControl } from 'react-leaflet-draw';

import useUserStore from '@/store/userStore';

import 'leaflet/dist/leaflet.css';
import 'leaflet-draw/dist/leaflet.draw.css';

interface DrawToolProps {
    drawedPolygons: Feature<Geometry, GeoJsonProperties>[];
    setDrawedPolygons: React.Dispatch<React.SetStateAction<Feature<Geometry, GeoJsonProperties>[]>>;
}

const DrawTool = ({ drawedPolygons, setDrawedPolygons }: DrawToolProps) => {
    // const map = useMap();
    const [featureGroup, setFeatureGroup] = useState<L.FeatureGroup | null>(null);

    useEffect(() => {
        console.log({ drawedPolygons });
    }, [drawedPolygons]);

    useEffect(() => {
        console.log({ featureGroup });
    }, [featureGroup]);

    const handleCreated = useCallback(
        (e: L.DrawEvents.Created) => {
            const { layerType, layer } = e;
            setDrawedPolygons((drawn: Feature<Geometry, GeoJsonProperties>[]) => [...drawn, layer.toGeoJSON()]); // if (layerType === 'polygon') {
            //     setPolygons([...polygons, layer.toGeoJSON()]);
            // } else if (layerType === 'polyline') {
            // const line = layer.toGeoJSON();
            // const newPolygons = polygons.flatMap((polygon) => {
            //     const cut = cutPolygonWithThickLine(polygon as Feature<Polygon, GeoJsonProperties>, line, 'cut_');
            //     console.log({ cut });
            //     return cut ? cut.features : [polygon];
            // });
            // setPolygons(newPolygons);
            // featureGroup?.clearLayers();
            // newPolygons.forEach((poly) => {
            //     L.geoJSON(poly).addTo(featureGroup as L.FeatureGroup);
            // });
            // }
        },
        [setDrawedPolygons, drawedPolygons]
    );

    return (
        <FeatureGroup ref={(fg) => setFeatureGroup(fg)}>
            <EditControl
                onCreated={handleCreated}
                draw={{
                    polyline: {
                        shapeOptions: {
                            color: '#000000',
                            fillColor: '#000000',
                        },
                    },
                    rectangle: false,
                    marker: false,
                    circlemarker: false,
                    polygon: {
                        allowIntersection: true,
                        showArea: true,
                        showLength: true,
                        // metric: ['ha'],
                        shapeOptions: {
                            color: 'lightgreen',
                            fillColor: 'lightgreen',
                        },
                    },
                    circle: false,
                }}
                position="topright"
            />
        </FeatureGroup>
    );
};

export default function DrawMap() {
    const user = useUserStore((state) => state.user);
    const [drawedPolygons, setDrawedPolygons] = useState<Feature[]>([]);

    return (
        <>
            <MapContainer
                key="draw-map"
                style={{ width: '100%', height: '100%' }}
                zoom={user?.zoom_agr || 13}
                center={[user?.lat_agr || 0, user?.lng_agr || 0]}
            >
                <TileLayer
                    attribution='&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors'
                    url="https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}"
                    maxZoom={20}
                    subdomains={['mt0', 'mt1', 'mt2', 'mt3']}
                />
                <DrawTool drawedPolygons={drawedPolygons} setDrawedPolygons={setDrawedPolygons} />
            </MapContainer>
        </>
    );
}