我正在使用react-leaflet版本4.x。
我试图通过单击按钮来更新地图的缩放级别,就像一个简单的用例一样。我意识到您可以为
<MapContainer>
创建一个子组件并使用 useMap()
,但我希望能够使用位于 <MapContainer>
组件外部的控件来更改地图。因此,我正在使用react-redux来尝试和管理状态。
我创建了一个切片,其缩放级别作为初始状态的一部分:
import { createSlice } from "@reduxjs/toolkit";
export const mapViewSlice = createSlice({
name: "mapView",
initialState: {
zoom: 5,
},
reducers: {
changeZoom: (state, action) => {
state.zoom = action.payload;
},
},
});
export const { changeZoom } = mapViewSlice.actions;
export default mapViewSlice.reducer;
然后我创建了
Map
组件,在单击按钮时调度 changeZoom
操作:
import React, { useState, useEffect, useRef } from "react";
import { useSelector, useDispatch } from "react-redux";
import { MapContainer, TileLayer } from "react-leaflet";
import { changeZoom } from "./mapViewSlice";
import "./Map.css";
export const Map = () => {
const mapRef = useRef(null);
const zoomLevel = useSelector((state) => state.mapView.zoom);
const dispatch = useDispatch();
return (
<div id="map-container" className="flex-container-row">
<MapContainer center={[37.0902, -95.7129]} zoom={zoomLevel} ref={mapRef}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
<button onClick={() => dispatch(changeZoom(2))}>Change Zoom</button>
</div>
);
};
如果我单击按钮并
console.log(zoomLevel)
,我会看到它按预期返回值2
。但我需要更新地图参考。我尝试放入 useEffect
来更新地图,但收到一条错误消息,表明 mapRef
无法正常工作:
useEffect(() => {
mapRef.current.setZoom(zoomLevel);
}, [zoomLevel]);
无法读取 null 的属性(读取“setZoom”) 类型错误:无法读取 null 的属性(读取“setZoom”)
我还尝试将参考更改为
whenReady
并使用 useState
来保存地图参考:
const [map, setMap] = useState(null)
//...
useEffect(() => {
if (map) {
console.log(map);
map.setZoom(zoomLevel);
}
}, [zoomLevel]);
//...
<MapContainer center={[37.0902, -95.7129]} zoom={zoomLevel} whenReady={setMap}>
//...
</MapContainer>
这给了我这样的错误:
map.setZoom 不是函数
我该怎么做?
编辑:我必须缺少从传单的导入才能访问
setZoom
功能,对吗?我如何获得这些方法?
原来我需要做的就是将
ref
设置为 <MapContainer>
并将其与 useState
而不是 useRef
一起使用。我在react-leaflet文档中找到了使用外部控件控制地图的示例。
我最终的
Map
组件代码:
import React, { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { MapContainer, TileLayer } from "react-leaflet";
import { changeZoom } from "./mapViewSlice";
import "./Map.css";
export const Map = () => {
const [map, setMap] = useState(null);
const zoomLevel = useSelector((state) => state.mapView.zoom);
const dispatch = useDispatch();
useEffect(() => {
if (map) {
map.setZoom(zoomLevel);
}
}, [zoomLevel, map]);
return (
<div id="map-container" className="flex-container-row">
<MapContainer center={[37.0902, -95.7129]} zoom={zoomLevel} ref={setMap}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
<button onClick={() => dispatch(changeZoom(2))}>Change Zoom</button>
</div>
);
};