setting state doesn't work properly when trying to set coordinates

218 Views Asked by At
function MyMap({ floorsByBuilding }: MyMapProps) {
  const [coords, setCoords] = useState<any[]>([]);

  const created = (e) => {
    const coordsList = e.layer.editing.latlngs[0][0];
    console.log("coordsList:", coordsList);
    setCoords(coordsList);
    console.log("Coords:",coords);
  };

  return (
    <div className="mapview">
      <div className="myMap">
        <Map center={[0, 0]} zoom={1}>
          <FeatureGroup>
            <EditControl
              position="topright"
              draw={{
                rectangle: false,
                circle: false,
                circlemarker: false,
                polyline: false,
              }}
              onCreated={created}
            />
          </FeatureGroup>
        </Map>
      </div>
    </div>
  );
}

e.layer.editing.latlngs[0][0] looks like,

[
   {
      "lat":32.29840589562344,
      "lng":80.85780182804785
   },
   {
      "lat":17.421213563227735,
      "lng":78.36653079164644
   },
   {
      "lat":23.02755815843566,
      "lng":107.33497479055386
   },
   {
      "lat":41.49329414356384,
      "lng":104.47883340910323
   },
   {
      "lat":39.47390998063457,
      "lng":82.8312041405605
   }
]

The EditControl is react-leaflet-draw component that helps to annotate in an image or map, from where we get coordinates (the above data) which is e.layer.editing.latlngs[0][0]. After getting the coordinates, i'm trying to store those coordinates into a state (which is setCoords) so that i can use those coordinates elsewhere.

The issue here is, after obtaining the coordsList for the first time, the setCoords doesn't actually set those coords ( the second console.log returns empty array, even if the first console.log does return desired output). But when i'm trying the second time, i.e a new coordList values are obtain, the setCoords sets the data of the pervious coordsList (the first console.log return the coordsList correctly but the second console.log return previous data of coordsList).

Screenshots for more clarity,

First time when I get coordsList,

enter image description here

Second time, enter image description here

3

There are 3 best solutions below

0
On BEST ANSWER

Because state only has new value when component re render. So you should move console.log to useEffect to check the new value when component re-render.

const created = (e) => {
  const coordsList = e.layer.editing.latlngs[0][0];
  console.log("coordsList:", coordsList);
  setCoords(coordsList);
};

useEffect(() => {
  console.log("Coords:", coords);
}, [coords]);
0
On

It's because Reactjs's update batching mechanism


When updating state within an eventHandler like onChange, onClick,.etc.., React will batch all of setState into one:

const created = (e) => {
  const coordsList = e.layer.editing.latlngs[0][0];
  console.log("coordsList:", coordsList);
  setCoords(coordsList);
  console.log("Coords:", coords);
};

Place your log right before return function to see that lastest value:

function MyMap({ floorsByBuilding }: MyMapProps) {
  const [coords, setCoords] = useState<any[]>([]);

  const created = (e) => {
    const coordsList = e.layer.editing.latlngs[0][0];
    setCoords(coordsList);
  };

  console.log("Coords:",coords);
  return (
  ...
  )
}

But this behaviour will be changed in Reactjs 18 as mentioned here

0
On

Keep console.log outside the created() function. setCoords() is an async function, as a result state won't be updated right away to show it in the console.log as you have given. So keep it outside to view it when re-rendering.

  const created = (e) => {
    const coordsList = e.layer.editing.latlngs[0][0];
    console.log("coordsList:", coordsList);
    setCoords(coordsList);
  };

   console.log("Coords:",coords);