如何将Leaflet Choropleth教程适配为react-leaflet v3函数组件版本
问题原因&修改方案
你遇到的两个功能失效的原因如下:
- 重置样式失效:
resetStyle()是GeoJSON图层实例的方法,不是单个矢量要素(feature)的方法,你之前在单个要素的mouseout事件里调用e.target.resetStyle()自然无法生效 - 缩放失效:事件对象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='© <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
相关产品推荐
相关产品推荐

