基于道具的 UseEffect 正在向状态数组添加重复项

UseEffect based on props is adding duplicates to state array

所以问题的简短描述

用户可以通过 html select tag select 半径,这个值作为 prop 发送到这个组件,如果值改变 useEffect 重新渲染

我现在实施它的方式,它产生了 filtered events 添加到 state 的问题。所以它不断地向数组添加重复项。

我如何使用 useEffect / setState 来确保以前的项目将被删除或覆盖并且只有唯一事件存储在 state 中?

const [data, setData] = useState();
const [userLat, setUserLat] = useState();
const [userLon, setUserLon] = useState();
const [evtsFiltered, setEvtsFiltered] = useState([]);

// Fetch all events and store in state
useEffect(() => {
  axios.get("http://localhost:5000/events").then((res) => {
    setData(res.data.events);
  });
}, []);

// Filter events based on user's location
useEffect(() => {
  data?.forEach((el) => {
    Geocode.fromAddress(`${el.address}`)
      .then((res) => {
        let dis = getPreciseDistance(
          {
            latitude: parseFloat(res.results[0].geometry.location.lat),
            longitude: parseFloat(res.results[0].geometry.location.lng),
          },
          { latitude: parseFloat(userLat), longitude: parseFloat(userLon) }
        );
        if (dis / 1000 <= props.radius) { // props.radius will trigger the useEffect when user selects a new value on the homepage
          setEvtsFiltered((evtsFiltered) => [...evtsFiltered, el]);
        }
      })
      .catch((err) => console.log(err));
  });
}, [data, userLon, userLat, props.radius]);

我知道行 setEvtsFiltered((evtsFiltered) => [...evtsFiltered, el]) 是错误的,因为我使用 spread operator. 将新事件与以前的事件一起存储问题是我不知道如何修复它。

如果有人能指出我正确的方向?

提前致谢!

我会将数据映射到一个承诺数组,并等待它们全部完成使用 Promise.all(),然后再用新数组替换当前状态。要删除不符合条件的项目,您可以 return 一个空数组,然后用 Array.flat() 展平结果以删除它们

示例(未测试):

useEffect(async() => {
  try {
    const evts = await Promise.all(
      data.map(async(el) => {
        const res = await Geocode.fromAddress(`${el.address}`);

        let dis = getPreciseDistance({
          latitude: parseFloat(res.results[0].geometry.location.lat),
          longitude: parseFloat(res.results[0].geometry.location.lng),
        }, {
          latitude: parseFloat(userLat),
          longitude: parseFloat(userLon)
        });

        return dis / 1000 <= props.radius ? el : [];
      })
    );

    setEvtsFiltered(evts.flat());
  } catch (e) {
    console.log(err);
  }
}, [data, userLon, userLat, props.radius]);