在React中为MapView添加onClick处理程序?

6
我正在使用ArcGIS API for JavaScript来显示地图,并且我想在有人点击地图时获取所选要素。这是我的MapComponent。
export const MapComponent = () => {
    const elementRef = useRef(null);
    const [view, setView] = useState<MapView>();
    const [selected, setSelected] = useState<Feature>();


    const handleClick = useCallback((e: any) => {
        if (!view) return;
        view.hitTest(e)
            .then(res => {
                if (res.results.length > 0) {
                    const feature = res.results[0];
                    if (feature.type === 'graphic') {
                        setSelected(feature.graphic.attributes)
                    }
                }
            })
    }, [view]);

    useEffect(() => {
        if (!view) return;
        const handle = view.on('click', handleClick)
        return handle && handle.remove();
    }, [view]);

    useEffect(() => {
        const loadMap = async () => {
            const { init } = await import('./Map');
            const mapView = init(elementRef.current);
            setView(mapView);
        }
        loadMap()
        return () => view && view.destroy();
    }, []);

    return (
        <>
            <div
                ref={elementRef}
                style={{ height: '500px', width: '800px' }}
            >
            </div>
            <pre>{JSON.stringify(selected, null, 2)}</pre>
        </>
    )
}

我在useEffect中初始化了地图,并使用useState保存了地图视图。根据文档,你需要在另一个useEffect中添加事件处理程序,我尝试过这样做,但是当我点击地图时,handleClick函数没有运行。

这段代码的作用是,如果view为空,则直接返回,而不继续执行下一行代码。 - Mark Schultheiss
如果(!view)则返回,而不是运行下一行?if (!view) return; - Mark Schultheiss
如果不是返回而是运行下一行呢? if (!view) return; - undefined
它确实运行了下一行代码,但是当我点击地图时,handleClick函数却没有运行。 - Luis Carlos Cruz Castillo
它确实换行了,但是当我点击地图时,handleClick函数却没有运行。 - Luis Carlos Cruz Castillo
3个回答

1
看起来你正在尝试向地图视图添加事件监听器来处理点击事件并获取所选要素。根据你提供的代码,似乎你在 useEffect 钩子中正确地添加了事件监听器,并使用 hitTest 方法来获取点击的要素。
你可以尝试在 handleClick 函数内部添加 console.log 语句,以查看在点击地图时是否调用了该函数。如果没有被调用,可能是事件监听器添加到地图视图上的方式有问题。
你还可以尝试将 handleClick 函数定义移动到添加事件监听器的 useEffect 钩子内部,以确保它能够访问最新的视图状态。
...
    const selectFeature = (selection: __esri.HitTestResult) => {
        console.debug(selection.results[0])
    }

    useEffect(() => {
        if (!view) return;
        const eventHandler = (e: __esri.ViewClickEvent) => {
            view.hitTest(e)
                .then(selectFeature)
                .catch(console.error)
        }

        const handler = view.on('click', eventHandler);

        return () => handler.remove();
    }, [view]);
...

0
你正在检查视图是否为假,然后在钩子中返回,这使得添加事件成为无法到达的代码。
useEffect(() => {
    if (!view) return;
    const handle = view.on('click', handleClick)
    return handle && handle.remove();
}, [view]);

当添加handleClick时,视图变量可能仍然为空,因为它在loadMap函数中是异步设置的。 在添加和移除事件的代码周围添加条件,以便只有在视图可用时才添加。
  useEffect(() => {
    if (view) {
      const handle = view.on("click", handleClick);
      return () => handle.remove();
    }
  }, [view, handleClick]);

我没工作,不是一样吗?如果视图没有一个假值,它将不会执行if语句内的代码。 - Luis Carlos Cruz Castillo
我没有工作,不是一样的吗?如果视图没有一个虚假值,它将不会执行if语句内的代码。 - Luis Carlos Cruz Castillo

-1
我从来就无法让hitTest起作用,所以我做了以下的替代方案:
view.popup.watch("selectedFeature", function(){
# do whatever
})

这还允许用户在点击堆叠功能后浏览弹出窗口,并根据其所查看的内容进行更改。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接