How to make dynamic changes in Arcgis JS map-component with React?

Viewed 93

I am quite new to Arcgis-JS and React. As suggested here, I am using a functional component with the useEffect hook to integrate my map.

Now I want to display a line within my map when I click on a certain row of a list. On click I am fetching the appropriate coordinates to be displayed and storing them to a context-variable (dbPageContext.currentGeom).

The problem: When I want to display another line, the entire map-component has to re-render as I am passing the line-array-variable as a second argument to the useEffect hook.

const MapComp = () => {
  const mapRef = useRef();
  const dbPageContext = useContext(DbPageContext);


  useEffect(() => {
    const mainMap = new Map({
      layers: [layer],
      basemap: "arcgis-topographic", // Basemap layer service
    });

    const graphicsLayer = new GraphicsLayer();
    mainMap.add(graphicsLayer);

    const polyline = {
      type: "polyline",
      paths: dbPageContext.currentGeom, 
    };
    const simpleLineSymbol = {
      type: "simple-line",
      color: [0, 230, 250], 
      width: 4,
    };

    const polylineGraphic = new Graphic({
      geometry: polyline,
      symbol: simpleLineSymbol,
    });
    graphicsLayer.add(polylineGraphic);

    const view = new MapView({
      container: mapRef.current,
      map: mainMap,
      spatialReference: {
        wkid: 3857,
      },
    });
    return () => {
      view && view.destroy();
    };
  }, [dbPageContext.currentGeom]);

  return (
    <div>
      <div className="webmap" ref={mapRef} />
    </div>
  );
};

export default MapComp;

How can I update only the graphics-layer without updating the entire map-component? Would be great if someone could help me finding a solution for that.

EDIT: I also tried to implement the map without using the useeffect hook. But then, nothing was displayed.

1 Answers

You need to separate the effects. On page load, you should have one effect that creates the map. Then a second effect can update the map when dbPageContext.currentGeom changes.

const MapComp = () => {
  const mapRef = useRef();
  const dbPageContext = useContext(DbPageContext);

  // Memoize this, as you only need to create it once, but you also need
  // it to be available within scope of both of the following useEffects
  const graphicsLayer = React.useMemo(
    () => new GraphicsLayer(), 
    []
  );

  // On mount, create the map, view, and teardown
  useEffect(() => {
    const mainMap = new Map({
      layers: [layer],
      basemap: "arcgis-topographic", // Basemap layer service
    });

    const view = new MapView({
      container: mapRef.current,
      map: mainMap,
      spatialReference: {
        wkid: 3857,
      },
    });

    mainMap.add(graphicsLayer);

    return () => {
      view && view.destroy();
    };
  }, [])

  // When dbPageContext.currentGeom changes, add a polyline
  // to the graphics layer
  useEffect(() => {
    const polyline = {
      type: "polyline",
      paths: dbPageContext.currentGeom, 
    };
    const simpleLineSymbol = {
      type: "simple-line",
      color: [0, 230, 250], 
      width: 4,
    };

    const polylineGraphic = new Graphic({
      geometry: polyline,
      symbol: simpleLineSymbol,
    });
 
    // Clear previously added lines (if that's what you want)
    graphicsLayer.removeAll()
    graphicsLayer.add(polylineGraphic);
  }, [dbPageContext.currentGeom]);

  return (
    <div>
      <div className="webmap" ref={mapRef} />
    </div>
  );
};

export default MapComp;
Related