问题描述
问题的简短描述
用户可以通过 html select tag
选择半径,此值作为 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 数组,并在使用新数组替换当前状态之前等待所有这些使用 Promise.all()
完成。要删除不符合条件的项目,您可以返回一个空数组,然后使用 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]);