首页 > 解决方案 > 如何在 React 中异步更新同一数组中的多个对象?

问题描述

我有一个应用程序,其类定义如下:

class Point {
  id: string;
  position: Coordinate;
  elevation?: number;
}

在我的应用程序中,我存储了一组点。

const [points, setPoints] = useState<Point[]>([]);

在下面的代码中,我有一个依赖于points数组的 useEffect 钩子;任何时间points变化,效果都会扫描具有undefined高程的点并异步查询高程。当单个查询返回时,将调用回调handleUpdatePoint以使用新的高程值更新该特定点。

  // Any time the Points array changes, checks each Point for undefined elevation
  // and queries for it
  //  ISSUE: If more than one elevation query has yet to resolve, there will be an unintended
  //         state if one query resolves while one or more queries are pending
  useEffect(() => {
    points.forEach((p) => {
      if (p.elevation === undefined) {
        ElevationQuery(p.position.lat, p.position.lng, (elevation) => {
          handleUpdatePoint(p.id, { elevation: elevation });
        });
      }
    });
  }, [handleUpdateSteerpoint, points]);`

我面临的问题是,如果多个查询同时挂起,则状态points会在多个结果返回时被覆盖,从而丢失我的某些查询的提升结果。我怎样才能解决这个问题?


编辑#1:handleUpdatePoint添加以供参考

const handleUpdatePoint = useCallback(
    (id: string, newPointData: Partial<Point>) => {
      // shallow copy the points array
      const pointsClone = [...points];

      // the point we are updating
      const targetPoint = getPointById(id);

      // preserve all other points as they are, but update the target point
      // with the new data
      const updatedPoints: Point[] = pointsClone.map((p: Point) => {
        if (p.id !== id) {
          return p;
        } else {
          // if the target point has a position, change its elevation to undefined
          if (newPointData.position) {
            newPointData.elevation = undefined;
          }

          const updatedPoint: Point = update(targetPoint, { $merge: newPointData })!;
          return updatedPoint;
        }
      });

      setPoints(updatedPoints);
    },
    [getPointById, points]
  );

标签: reactjsasynchronoususe-effect

解决方案


只需使用回调样式更新您的状态就可以解决问题:

setPoints((previousPoints) =>
  previousPoints.map((p: Point) => {
    if (p.id !== id) {
      return p;
    } else {
      // if the target point has a position, change its elevation to undefined
      if (newPointData.position) {
        newPointData.elevation = undefined;
      }

      const updatedPoint: Point = update(targetPoint, {
        $merge: newPointData,
      })!;
      return updatedPoint;
    }
  })
);

推荐阅读