Add onClick handler to MapView in React?
Asked Answered
K

2

6

I'm using the ArcGIS API for JavaScript to display a map and I want to get the selected feature when someone clicks on the map. This is my 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>
        </>
    )
}

I initialized the map in a useEffect and save the map view with useState, I saw in the documentation you have to add your event handlers on another useEffect and I tried to do that, but the function handleClick doesn't run when I click on the map

Kaohsiung answered 9/7, 2023 at 21:30 Comment(2)
does this return rather than running the next line? if (!view) return;Bradbury
It does run the next line, but the function handleClick does not run when I click on the mapKaohsiung
C
1

It seems like you’re trying to add an event listener to the map view to handle clicks and get the selected feature. From the code you provided, it looks like you’re correctly adding the event listener in a useEffect hook and using the hitTest method to get the clicked feature.

One thing you could try is to add a console.log statement inside the handleClick function to see if it’s being called when you click on the map. If it’s not being called, there might be an issue with how the event listener is being added to the map view.

You could also try moving the handleClick function definition inside the useEffect hook where you’re adding the event listener, to make sure that it has access to the latest view state.

...
    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]);
...
Carpus answered 12/7, 2023 at 15:45 Comment(0)
C
0

You are checking if view is falsy, then returning out of the hook, and that makes adding the event unreachable code.

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

The view variable is probably still null when handleClick is added, since it's set asynchronously in the loadMap function. Add a conditional around the code that adds and removes the event so it's only added when the view is available.

  useEffect(() => {
    if (view) {
      const handle = view.on("click", handleClick);
      return () => handle.remove();
    }
  }, [view, handleClick]);
Crouch answered 17/7, 2023 at 21:54 Comment(1)
I didn't work, isn't it the same? if the view has not a falsy value it will not run the code inside the ifKaohsiung

© 2022 - 2024 — McMap. All rights reserved.