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

如何将Leaflet Choropleth教程适配为react-leaflet v3函数组件版本

问题原因&修改方案

你遇到的两个功能失效的原因如下:

  1. 重置样式失效:resetStyle()是GeoJSON图层实例的方法,不是单个矢量要素(feature)的方法,你之前在单个要素的mouseout事件里调用e.target.resetStyle()自然无法生效
  2. 缩放失效:事件对象e本身没有fitBounds方法,你需要先拿到react-leaflet的地图实例才能调用这个方法

具体修改步骤如下:

第一步:引入所需钩子

react-leaflet v3提供了useMap钩子来获取地图实例,同时你需要用useRef来保存GeoJSON图层的引用

import { useRef } from 'react'
import { MapContainer, TileLayer, Marker, Popup, GeoJSON, useMap } from 'react-leaflet'

第二步:获取地图实例、声明GeoJSON引用

在MainMap组件内部最开头添加两行代码:

const map = useMap()
const usGeoJsonRef = useRef(null)

第三步:修正两个失效的方法

const resetHighlight = (e) => {
  // 调用GeoJSON实例的resetStyle方法重置对应要素样式
  usGeoJsonRef.current.resetStyle(e.target)
}

const zoomToFeature = (e) => {
  // 用地图实例调用fitBounds缩放到要素范围
  map.fitBounds(e.target.getBounds())
}

第四步:给US的GeoJSON组件绑定ref

找到原来写US GeoJSON的代码行,修改为:

<GeoJSON ref={usGeoJsonRef} data={usMapData.features} style={geoStyleUS} onEachFeature={onEachFeature}/>

代码规范优化建议

  • 你写函数的时候外层多了不必要的括号,比如const onEachFeature = ((feature, layer) => {直接改成const onEachFeature = (feature, layer) => {即可,多余的括号会增加不必要的理解成本
  • 三个地区的样式除了边框颜色其他完全一致,可以抽成公共函数复用,减少重复代码:
    const getGeoStyle = (color) => ({
      fillColor: 'white',
      weight: 2,
      opacity: 1,
      color: color,
      dashArray: '3',
      fillOpacity: 0.5
    })
    // 用的时候直接传颜色就行:getGeoStyle('red')、getGeoStyle('blue')、getGeoStyle('green')
    
  • 地图中心点、默认缩放等级这些固定参数可以提前定义成常量,后续修改的时候不用找JSX结构里的属性
  • 如果你后续要给加拿大、墨西哥也加同样的交互,只要给对应的GeoJSON也加ref,然后单独写对应的onEachFeature方法即可

修改后完整代码

import '../App.css';
import { useRef } from 'react'
import caMapData from '../data/caProvince.json'
import mxMapData from '../data/mxStates.json'
import usMapData from '../data/usStates.json'

import { MapContainer, TileLayer, Marker, Popup, GeoJSON, useMap } from 'react-leaflet'

// 抽离公共常量
const DEFAULT_CENTER = [44.967243, -103.771556]
const DEFAULT_ZOOM = 4

// 抽离公共样式生成函数
const getGeoStyle = (color) => ({
  fillColor: 'white',
  weight: 2,
  opacity: 1,
  color: color,
  dashArray: '3',
  fillOpacity: 0.5
})

function MainMap() {
  const map = useMap()
  const usGeoJsonRef = useRef(null)

  const onEachFeature = (feature, layer) => {
    layer.on({
      mouseover: highlightFeature,
      mouseout: resetHighlight,
      click: zoomToFeature
    });
  }

  const highlightFeature = (e) => {
    e.target.bringToFront();
    e.target.setStyle({
      weight: 5,
      color: '#666',
      dashArray: '',
      fillOpacity: 0.7
    });
  }

  const resetHighlight = (e) => {
    usGeoJsonRef.current.resetStyle(e.target);
  }

  const zoomToFeature = (e) => {
    map.fitBounds(e.target.getBounds());
  }

  return(
    <MapContainer
      center={DEFAULT_CENTER}
      zoom={DEFAULT_ZOOM}
      scrollWheelZoom={true}>
      <TileLayer
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      <Marker position={DEFAULT_CENTER}>
        <Popup>
          Middle of US.
        </Popup>
      </Marker>
      <GeoJSON data={caMapData.features} style={getGeoStyle('red')}/>
      <GeoJSON ref={usGeoJsonRef} data={usMapData.features} style={getGeoStyle('blue')} onEachFeature={onEachFeature}/>
      <GeoJSON data={mxMapData.features} style={getGeoStyle('green')}/>
    </MapContainer>
  );
}

export default MainMap;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 22:15:03