Reactjs 基于道具的UseEffect正在向状态数组添加副本

Reactjs 基于道具的UseEffect正在向状态数组添加副本,reactjs,react-hooks,react-state,Reactjs,React Hooks,React State,所以,请简要描述一下这个问题 用户可以通过html选择标记选择半径,该值作为道具发送到此组件,如果该值更改useffect重新渲染器 我现在实现它的方式产生了一个问题,过滤事件被添加到状态。因此它不断地向数组中添加重复项 如何使用useffect/setState确保删除或覆盖以前的项目,并且在状态中只存储唯一的事件 const [data, setData] = useState(); const [userLat, setUserLat] = useState(); const [userL

所以,请简要描述一下这个问题

用户可以通过
html选择标记
选择半径,该值作为
道具
发送到此组件,如果该值更改
useffect
重新渲染器

我现在实现它的方式产生了一个问题,
过滤事件
被添加到
状态
。因此它不断地向数组中添加重复项

如何使用
useffect/setState
确保删除或覆盖以前的项目,并且在
状态中只存储唯一的事件

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]);
const[data,setData]=useState();
const[userLat,setUserLat]=useState();
const[userLon,setUserLon]=useState();
const[evtsFiltered,setEvtsFiltered]=useState([]);
//获取所有事件并以状态存储
useffect(()=>{
axios.get(“http://localhost:5000/events)然后((res)=>{
setData(res.data.events);
});
}, []);
//根据用户的位置筛选事件
useffect(()=>{
数据?.forEach((el)=>{
Geocode.fromAddress(`${el.address}`)
。然后((res)=>{
让dis=获得精确距离(
{
纬度:parseFloat(res.results[0].geometry.location.lat),
经度:parseFloat(res.results[0].geometry.location.lng),
},
{纬度:parseFloat(userLat),经度:parseFloat(userLon)}
);
如果(dis/1000[…evtsFiltered,el]);
}
})
.catch((err)=>console.log(err));
});
},[data,userLon,userLat,props.radius];
我知道行
setEvtsFiltered((evtsFiltered)=>[…evtsFiltered,el])
是错误的,因为我使用
spread操作符将新事件与以前的事件一起存储。
问题是我不知道如何修复它

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


提前谢谢

我会将数据映射到承诺数组,并等待所有承诺都使用
Promise.all()
,然后用新数组替换当前状态。要删除与条件不匹配的项,可以返回一个空数组,然后使用
array.flat()
将结果展平以删除它们

示例(未测试):

useffect(async()=>{
试一试{
const evts=等待承诺。全部(
data.map(异步(el)=>{
const res=wait Geocode.fromAddress(`${el.address}`);
让dis=获得精确距离({
纬度:parseFloat(res.results[0].geometry.location.lat),
经度:parseFloat(res.results[0].geometry.location.lng),
}, {
纬度:parseFloat(userLat),
经度:parseFloat(userLon)
});

return dis/1000这是一个很好的干净解决方案,尽管我更喜欢。我真的不明白为什么人们会如此回避它。非常感谢Ori Drori,它的工作方式很有魅力!@trixn你能不能也给我一个使用reduce的解决方案?@trixn从一个数组减少到一个数组没有那么惯用,我们有这方面的地图。
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]);