在 useEffect 之外使用传单地图对象进行反应
Use leaflet map object outside useEffect in react
我有一个按钮可以编辑 mymap 对象(例如添加标记或圆圈)。
但它给我的错误是“mymap is not defined”。
我曾尝试在 useEffect 之外声明 mymap var,但它不起作用,因为 useEffect 不保存分配。我也试过 useState 但它也不起作用。
这是我的代码
import 'leaflet/dist/leaflet.css'
import L from 'leaflet/dist/leaflet'
import { useEffect, useState} from 'react'
import './css/grid.css'
export const Grid = ({mapID}) => {
const centerCoor = //redacted
var layerGroup = L.layerGroup()
function addGrid(){
var btnel = document.getElementById("btn-grid");
btnel.classList.toggle("btn-active");
if (btnel.classList.contains("btn-active")){
// do something with "mymap"
mymap.on('click', (e)=>{
})
}
}
useEffect(()=>{
var mymap = L.map(mapID, {
center: centerCoor,
zoom:18
});
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
attribution: 'Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox/satellite-v9',
tileSize: 512,
zoomOffset: -1,
accessToken: //redacted
}
).addTo(mymap);
return () => {
mymap.off()
mymap.remove()
}
},[])
return (
<div>
<button onClick={addGrid} className="" id="btn-grid">ADD GRID</button>
<div id={mapID}>
</div>
</div>
)
}
Leaflet 独立于 React 跟踪其状态,这就是为什么最好使用 React-Leaflet binding。如果你打算在 React 中使用 vanilla Leaflet,你应该考虑设置一个 useEffect
钩子来处理创建地图实例并将地图实例设置为状态。然后你可以访问地图实例来添加事件监听器,添加 markers/popups 等。这也有助于 React 跟踪 Leaflet 的当前状态并监视任何更改。这是一个示例组件:
import React, { useEffect, useRef, useState } from 'react';
import L from 'leaflet';
const MapComponent = (props) => {
// Map state:
const [mapInstance, setMapInstance] = useState(null);
const [marker, setMarker] = useState(null);
// Map refs:
const mapRef = useRef(null);
const tileRef = useRef(null);
const markerRef = useRef(null);
// Base tile for the map:
tileRef.current = L.tileLayer(
`https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`,
{
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}
);
const mapStyles = {
overflow: 'hidden',
width: '100%',
height: '100vh',
};
// Options for our map instance:
const mapParams = {
center: [37.0902, -95.7129], // USA
zoom: 3,
zoomControl: false,
zoomSnap: 0.75,
layers: [tileRef.current], // Start with just the base layer
};
// Map creation:
useEffect(() => {
mapRef.current = L.map('map', mapParams);
// Add an event listener:
mapRef.current.on('click', () => {
alert('map clicked');
});
// Set map instance to state:
setMapInstance(mapRef.current);
}, []); // <- Empty dependency array, so it only runs once on the first render.
// If you want to use the mapInstance in a useEffect hook,
// you first have to make sure the map exists. Then, you can add your logic.
useEffect(() => {
// Check for the map instance before adding something (ie: another event listener).
// If no map, return:
if (!mapInstance) return;
if (mapInstance) {
mapInstance.on('zoomstart', () => {
console.log('Zooming!!!');
});
}
}, [mapInstance]);
// Toggle marker on button click:
const handleClick = () => {
if (marker) {
marker.removeFrom(mapInstance);
markerRef.current = null;
} else {
markerRef.current = L.marker([40.7128, -74.006]).addTo(mapInstance);
}
setMarker(markerRef.current);
};
return (
<>
<button onClick={handleClick}>
{`Click to ${marker ? 'remove' : 'add'} marker`}
</button>
<div id="map" style={mapStyles} />
</>
);
};
export default MapComponent;
这是我设置的实时沙箱,您可以对其进行测试:
LIVE DEMO
我有一个按钮可以编辑 mymap 对象(例如添加标记或圆圈)。 但它给我的错误是“mymap is not defined”。 我曾尝试在 useEffect 之外声明 mymap var,但它不起作用,因为 useEffect 不保存分配。我也试过 useState 但它也不起作用。
这是我的代码
import 'leaflet/dist/leaflet.css'
import L from 'leaflet/dist/leaflet'
import { useEffect, useState} from 'react'
import './css/grid.css'
export const Grid = ({mapID}) => {
const centerCoor = //redacted
var layerGroup = L.layerGroup()
function addGrid(){
var btnel = document.getElementById("btn-grid");
btnel.classList.toggle("btn-active");
if (btnel.classList.contains("btn-active")){
// do something with "mymap"
mymap.on('click', (e)=>{
})
}
}
useEffect(()=>{
var mymap = L.map(mapID, {
center: centerCoor,
zoom:18
});
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
attribution: 'Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox/satellite-v9',
tileSize: 512,
zoomOffset: -1,
accessToken: //redacted
}
).addTo(mymap);
return () => {
mymap.off()
mymap.remove()
}
},[])
return (
<div>
<button onClick={addGrid} className="" id="btn-grid">ADD GRID</button>
<div id={mapID}>
</div>
</div>
)
}
Leaflet 独立于 React 跟踪其状态,这就是为什么最好使用 React-Leaflet binding。如果你打算在 React 中使用 vanilla Leaflet,你应该考虑设置一个 useEffect
钩子来处理创建地图实例并将地图实例设置为状态。然后你可以访问地图实例来添加事件监听器,添加 markers/popups 等。这也有助于 React 跟踪 Leaflet 的当前状态并监视任何更改。这是一个示例组件:
import React, { useEffect, useRef, useState } from 'react';
import L from 'leaflet';
const MapComponent = (props) => {
// Map state:
const [mapInstance, setMapInstance] = useState(null);
const [marker, setMarker] = useState(null);
// Map refs:
const mapRef = useRef(null);
const tileRef = useRef(null);
const markerRef = useRef(null);
// Base tile for the map:
tileRef.current = L.tileLayer(
`https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`,
{
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}
);
const mapStyles = {
overflow: 'hidden',
width: '100%',
height: '100vh',
};
// Options for our map instance:
const mapParams = {
center: [37.0902, -95.7129], // USA
zoom: 3,
zoomControl: false,
zoomSnap: 0.75,
layers: [tileRef.current], // Start with just the base layer
};
// Map creation:
useEffect(() => {
mapRef.current = L.map('map', mapParams);
// Add an event listener:
mapRef.current.on('click', () => {
alert('map clicked');
});
// Set map instance to state:
setMapInstance(mapRef.current);
}, []); // <- Empty dependency array, so it only runs once on the first render.
// If you want to use the mapInstance in a useEffect hook,
// you first have to make sure the map exists. Then, you can add your logic.
useEffect(() => {
// Check for the map instance before adding something (ie: another event listener).
// If no map, return:
if (!mapInstance) return;
if (mapInstance) {
mapInstance.on('zoomstart', () => {
console.log('Zooming!!!');
});
}
}, [mapInstance]);
// Toggle marker on button click:
const handleClick = () => {
if (marker) {
marker.removeFrom(mapInstance);
markerRef.current = null;
} else {
markerRef.current = L.marker([40.7128, -74.006]).addTo(mapInstance);
}
setMarker(markerRef.current);
};
return (
<>
<button onClick={handleClick}>
{`Click to ${marker ? 'remove' : 'add'} marker`}
</button>
<div id="map" style={mapStyles} />
</>
);
};
export default MapComponent;
这是我设置的实时沙箱,您可以对其进行测试: LIVE DEMO