我正在尝试使用 React Leaflet 构建这个小项目,其中通过在 leaflet-geosearch 搜索栏搜索某个城市,点击它后,应该会弹出一个表单,询问有关该地点的一些评论。我想使用我作为 prop 传递给 SearchBar 组件的已评级地点数组,在地理搜索栏的处理程序中添加一个防止重复子句。当我尝试验证城市 arr 是否已经有一个具有相同 id 的对象时,它只是不提前返回,它完全忽略提前返回。
代码///
export default function SearchBar({
onSubmitCityMapSearch,
setCurrLocation,
onSetFocus,
cities,
}) {
function handler(event) {
const {
location: {
label,
y,
x,
raw: { place_id },
},
} = event;
const exists = cities.every((city) => city.location.id !== place_id);
if (!exists) {
console.log("It exists"); /*used to be an early return which wouldn't get executed. In this case the cl does get executed, same as the else block*/
} else {
onSubmitCityMapSearch();
setCurrLocation({ label, location: [y, x], id: place_id });
onSetFocus(place_id);
}
}
const provider = new OpenStreetMapProvider();
const searchControl = new GeoSearchControl({
provider: provider,
style: "bar",
showMarker: false,
});
const map = useMap();
useEffect(() => {
map.addControl(searchControl);
return () => map.removeControl(searchControl);
}, []);
map.on("geosearch/showlocation", handler);
return null;
}
我尝试使用 if/else 语句,在这种情况下它会执行 if 和 else 语句。我尝试对此进行一些研究,但无济于事。任何人都对为什么会发生这种情况有更深入的了解吗?代码有点乱,我对 React 还很陌生。
每次渲染组件时,您都会添加处理程序,因此最终会附加处理程序函数的多个版本,这些版本会覆盖 cities
的不同副本。因此,当事件发生时,您的处理程序会被多次调用,并报告对其
cities
副本有效的结果。如果您看到 if
分支和 else
分支都被采用,这是因为其中一个处理程序正在采用 if
分支,而 另一个处理程序正在采用
else
分支。您至少有两个选择:
useEffect
回调中以
cities
作为依赖项挂钩您的处理程序,并在效果的清理中取消挂钩(在任何情况下您都应该这样做),如下所示:useEffect(() => {
function handler(event) {
const {
location: {
label,
y,
x,
raw: { place_id },
},
} = event;
const exists = cities.every(
(city) => city.location.id !== place_id
);
if (!exists) {
console.log(
"It exists"
); /*used to be an early return which wouldn't get executed. In this case the cl does get executed, same as the else block*/
} else {
onSubmitCityMapSearch();
setCurrLocation({ label, location: [y, x], id: place_id });
onSetFocus(place_id);
}
}
map.on("geosearch/showlocation", handler);
return () => {
// This function is called when cleaning up
map.off("geosearch/showlocation", handler);
// ^^^−−−− or whatever the "unregister" function is
}
}, [cities]);
请注意,这意味着您的处理程序将被删除,并且每次
cities
更改时都会附加新的处理程序。在大多数情况下,这是无害的。
cities
,以便始终访问它的最新版本。一种常见的方法是使用 ref。您可以通过在组件函数内的顶级代码中声明 ref 并为其分配
cities
来实现这一点,然后在 useEffect(___, [])
回调中连接事件处理程序,该回调仅在挂载时运行,并让代码使用citiesRef.current
代替cities
:const citiesRef = useRef(null);
citiesRef.current = cities;
useEffect(() => {
function handler(event) {
const {
location: {
label,
y,
x,
raw: { place_id },
},
} = event;
const cities = citiesRef.current; // <================================
const exists = cities.every(
(city) => city.location.id !== place_id
);
if (!exists) {
console.log(
"It exists"
); /*used to be an early return which wouldn't get executed. In this case the cl does get executed, same as the else block*/
} else {
onSubmitCityMapSearch();
setCurrLocation({ label, location: [y, x], id: place_id });
onSetFocus(place_id);
}
}
map.addControl(searchControl);
map.on("geosearch/showlocation", handler);
return () => {
map.removeControl(searchControl);
map.off("geosearch/showlocation", handler);
// ^^^−−−− or, again, whatever the "unregister" function is
}
}, []);
这是可行的,因为
citiesRef
是对对象的
stable引用(它将始终指向同一个对象,在对组件函数的调用中保持一致),并且我们在每次调用时更新
citiesRef.current
,因此处理程序始终使用最新版本的城市。