ReactJS 同时执行 if 和 else 语句

问题描述 投票:0回答:1

我正在尝试使用 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 还很陌生。

reactjs leaflet react-leaflet
1个回答
0
投票

每次渲染组件时,您都会添加处理程序,因此最终会附加处理程序函数的多个版本,这些版本会覆盖 cities不同副本。因此,当事件发生时,您的处理程序会被多次调用,并报告对其

cities
副本有效的结果。如果您看到
if
分支和
else
分支都被采用,这是因为其中一个处理程序正在采用
if
分支,而
另一个
处理程序正在采用 else 分支。
您至少有两个选择:

  1. 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

    更改时都会附加新的处理程序。在大多数情况下,这是无害的。

    
    

  2. 如果由于某种原因您只想附加处理程序一次,则需要采用不同的方式来访问
  3. 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,因此处理程序始终使用最新版本的城市。
    
    

© www.soinside.com 2019 - 2024. All rights reserved.