Home > Software engineering >  I listen the data from socket.When I receive the data, I update the array like this .but state is no
I listen the data from socket.When I receive the data, I update the array like this .but state is no

Time:03-24

socket?.on('addLocation', data => {
  console.log('addLocation', data);
  let isFound = false;
  let newMarkers = markers.map(marker => {
    if (marker.fleet_id == data.fleetId) {
      isFound = false;
      return {
        ...marker,
        latitude: data.lat,
        longitude: data.long,
      };
    } else {
      return marker;
    }
  });

  if (!isFound) {
    newMarkers = [
      ...newMarkers,
      {
        fleet_id: data.fleetId,
        latitude: data.lat,
        longitude: data.long,
      },
    ];
  }
  setMarker(newMarkers);
})

CodePudding user response:

Assuming markers the state that setMarker is updating then this appears to be an issue of a stale enclosure over the markers state. The callback is updating the closed over state and not the current markers state value.

Use a functional state update to correctly access the previous state instead of the stale value. Array.prototype.map is meant to map one set of values to another, and shouldn't have side-effects like setting an isFound flag. Search the data first to decide if the state needs to be updated or if a new element needs to be appended.

Example:

socket?.on('addLocation', data => {
  console.log('addLocation', data);
  setMarker(markers => {
    const isFound = markers.some(marker => marker.fleet_id == data.fleetId);

    if (isFound) {
      return markers.map(marker => marker.fleet_id == data.fleetId
        ? {
          ...marker,
          latitude: data.lat,
          longitude: data.long,
        }
        : marker
      );
    }

    return [
      ...markers,
      {
        fleet_id: data.fleetId,
        latitude: data.lat,
        longitude: data.long,
      },
    ];
  });
});

CodePudding user response:

socket?.on('addLocation', ({ fleetId, lat, long }) => {
  setMarkers(existing => {
    const latLng = { latitude: lat, longitude: long };
    const index = existing.findIndex(m => m.fleet_id === fleetId);
    if (index === -1) {
      return [...existing, {
        fleet_id: fleetId,
        ...latLng
      }]
    } else {
      const clone = [...existing];
      clone[index] = {
        ...clone[index],
        ...latLng
      }
      return clone;
    }
  });
});

There are a few things here:

  1. You should use the callback flavour of setMarkers to ensure you have the "latest" copy when you're modifying it.
  2. The code as written is pretty convoluted, you can simplify it a lot. isFound will always be false is also a logic issue.
  • Related