How to post a created React Leaflet layer to an API?

406 Views Asked by At

I want to draw a polygon in react-leaflet and post the created layer to an API. Beside that, there are different tasks which are hold in the data state. The currently active task is hold in the activeTask. data and activeTask are both provided by a context. Everytime I post a layer, I want to add the taskId of the currently active task. The problem is: When I post the layer and the taskId, the taskId is empty. So in the first console.log (called "activeTask 1") the activeTask is not empty, so everything is fine. But in the second console.log (called "activeTask 2") the activeTask is empty. How can I access the activeTask to post the _id of it to an API?

import React, { useContext } from 'react';
import axios from 'axios';

import { MapContainer, TileLayer, Marker, Popup, FeatureGroup, GeoJSON } from 'react-leaflet';
import { EditControl } from 'react-leaflet-draw';
import 'leaflet/dist/leaflet.css';
import 'leaflet-draw/dist/leaflet.draw.css';

import { DataContext } from './DataContext';


const LeafletComponent = () => {
    const { dataContext, activeTaskContext } = useContext(DataContext);
    const [activeTask, setActiveTask] = activeTaskContext;
    const [data, setData] = dataContext;
    const position = [51.505, -0.09]
    let listAreas = [];
    for (let i = 0; i < data.length; i++) {
        if ("taskArea" in data[i]) {
            for (let j = 0; j < data[i].taskArea.length; j++) {
                if ("areaBoundaries" in data[i].taskArea[j]) {
                    listAreas.push(<GeoJSON key={data[i].taskArea[j]._id} data={JSON.parse(data[i].taskArea[j].areaBoundaries)} />);
                }
            }
        }
    }

    console.log("activeTask 1");
    console.log(activeTask);

    const _onCreated = async (e) => {
        console.log("activeTask 2");
        console.log(activeTask);// <-- this activeTask is empty
        const layer = e.layer;
        const geoj = layer.toGeoJSON();
        const postData = {
            taskId: activeTask._id,// <-- this activeTask is empty
            areaBoundaries: JSON.stringify(geoj)
        }
        try {
            const response = await axios.post('http://localhost:3333/createarea', postData);
            // do something with response
        } catch (error) {
            console.log(error);
        }
    };

    return (
        <MapContainer center={position} zoom={13} scrollWheelZoom={true}>
            <FeatureGroup>
                <EditControl position="topright" onCreated={_onCreated} draw={{
                    marker: false,
                    circle: false,
                    circlemarker: false,
                    rectangle: true,
                    polyline: false,
                    polygon: true
                }} />
            </FeatureGroup>
            <TileLayer
                attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            />
            {listAreas}
        </MapContainer>
    )
}

export default LeafletComponent;
1

There are 1 best solutions below

1
On

Did you tried to implement the _onCreated as a useCallback with dependency on the activeTask. Like this

const _onCreated = React.useCallback(async (e) => {
       //... 
}, [activeTask]);

React -> useCallback

You could also think about putting your for loop into a useMemo

const listAreas = React.useMemo(() => {
...
}, [data])

And maybe even use something like ramdajs to simplify your nested loop like this

pipe(
  map(x => x.taskArea),  
  flatten,
  filter(x => x && x.areaBoundaries)
  map(x => (<GeoJSON key... />))
)(data)