You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React ArcGIS项目API Key放置位置及FeatureLayer不显示问题

问题根因
  • API Key配置规则:Key不需要单独传给Map或者FeatureLayer组件,只要在初始化逻辑里给esriConfig.apiKey赋值即可全局生效,底图正常加载已经说明Key配置本身是有效的。
  • 模块解构顺序错位:你传入loadModules的模块列表,和回调里解构的变量顺序不匹配,从esri/layers/GeoJSONLayer开始所有类全部对应错误,你代码里调用的new FeatureLayer()实际拿到的是GraphicsLayer构造函数,根本无法生成正确的FeatureLayer实例。
  • 无效DOM操作中断执行:你调用view.ui.add("infoDiv", "bottom-left")时,JSX里不存在id为infoDiv的元素,这行代码会直接抛出JS错误,中断后续所有FeatureLayer创建、状态更新的逻辑,这就是featureLayer1一直为null显示Empty的直接原因。
  • useEffect缺少依赖数组:当前useEffect没有传第二个参数,会在组件每次重渲染时重复执行,触发状态更新→重渲染→重新初始化地图的死循环,即使前面的错误修复,也会导致地图实例反复创建、状态异常覆盖。
修复方案

首先修正模块解构顺序、删除无效DOM操作、给useEffect添加空依赖数组确保地图只初始化一次,同时添加实例销毁逻辑避免内存泄漏,修复后的完整代码如下:

import React, { useEffect, useRef, useState } from "react";
import { loadModules } from "esri-loader";


function Map() {
  
  const [featureLayer1, setFeatureLayer1] = useState(null);
  const viewRef = useRef(null);
  const MapElement = useRef(null);
  
  useEffect(() => {
    loadModules(
      [
        "esri/views/MapView",
        "esri/Map",
        "esri/config",
        "esri/layers/GeoJSONLayer",
        "esri/Graphic",
        "esri/layers/GraphicsLayer",
        "esri/layers/FeatureLayer",
        "esri/renderers/SimpleRenderer",
        "esri/symbols/SimpleFillSymbol",
        "esri/widgets/Legend",
      ],
      {
        css: true,
      }
    ).then(
      ([
        MapView,
        Map,
        esriConfig,
        GeoJSONLayer,
        Graphic,
        GraphicsLayer,
        FeatureLayer,
        SimpleRenderer,
        SimpleFillSymbol,
        Legend,
      ]) => {
        const houseStatus = {
          Unreleased: [99, 97, 97],
          Sold: [255, 0, 0],
          Available: [0, 255, 0],
          Other: [0, 0, 255],
        };

        esriConfig.apiKey = "MY_API_KEY";

        const map = new Map({
          basemap: "arcgis-imagery", 
        });

        const view = new MapView({
          map: map,
          center: [18.9660638, -33.8071444], 
          zoom: 13,
          container: MapElement.current,
        });
        viewRef.current = view;

        const graphicsLayer = new GraphicsLayer();
        graphicsLayer.opacity = 0.5;
        map.add(graphicsLayer);

        const streetLayer = new FeatureLayer({
          url: "https://services5.arcgis.com/WPkXI1mQdYLzFttB/arcgis/rest/services/Navigation_Barriers/FeatureServer/0",
        });
        // 捕获图层加载错误方便排查
        streetLayer.when(() => {
          setFeatureLayer1(streetLayer);
        }).catch(err => console.error("streetLayer加载失败:", err));
        
        const erfLayer = new FeatureLayer({
          url: "https://services5.arcgis.com/WPkXI1mQdYLzFttB/arcgis/rest/services/VdV_Cadastral/FeatureServer/0",
        });

        const valdevieLabels = {
          symbol: {
            type: "text",
            color: "#FFFFFF",
            haloColor: "#5E8D74",
            haloSize: "2px",
            font: {
              size: "12px",
              family: "Noto Sans",
              style: "italic",
              weight: "normal",
            },
          },
          labelPlacement: "center-center",
          labelExpressionInfo: {
            expression: "$feature.Label",
          },
        };
        const dotLayer = new FeatureLayer({
          url: "https://services5.arcgis.com/WPkXI1mQdYLzFttB/arcgis/rest/services/Greater_VdV_Addresses/FeatureServer/0",
          labelingInfo: [valdevieLabels],
        });
        dotLayer.opacity = 0;

        let symbol = {
          type: "simple-fill", 
          color: [51, 51, 204, 0.9],
          style: "none",
          outline: {
            color: "black",
            width: 1,
          },
        };
        const erfLayerRenderer = {
          type: "simple",
          symbol: symbol,
        };
        erfLayer.renderer = erfLayerRenderer;
        map.add(streetLayer);
        map.add(dotLayer);
        map.add(erfLayer);
      }
    );
    
    // 组件卸载时销毁地图实例,防止内存泄漏
    return () => {
      if (viewRef.current) {
        viewRef.current.destroy();
      }
    }
  // 空依赖数组,确保只在组件挂载时执行一次初始化
  }, []);

  return (
    <>
      <div style={{ height: 800 }} ref={MapElement}>
        {featureLayer1 !== null ? "Not empty" : "Empty"}
      </div>
    </>
  );
}

export default Map;
注意事项
  • 用esri-loader对接ArcGIS JS API时,loadModules的模块列表顺序必须和解构的变量顺序严格一一对应,否则会出现类引用错误,这类问题可以直接在浏览器控制台看到明确的类型报错。
  • 所有对DOM的操作要确保对应元素已经渲染,不要引用不存在的DOM节点,否则会中断JS执行流程。
  • React的useEffect做一次性初始化逻辑时,必须传空数组作为第二个参数,否则会重复执行逻辑引发异常。

内容的提问来源于stack exchange,提问作者Jacobus Jacobs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:48:51