Реакция листовки на получение экземпляра карты в функциональном компоненте

#javascript #reactjs #leaflet #react-leaflet

#javascript #reactjs #листовка #реагировать-листовка #реагировать-листовка-v3

Вопрос:

Я хочу иметь кнопку вне карты, которая изменяет вид на другие координаты.

Есть ли какой-либо способ заставить экземпляр mapContainer вызывать свои функции? Или как я могу реализовать эту функцию?

Я пытался получить его с помощью ссылки, но это не работает. Вот мой текущий код

 const zoom = 13;

function Map({ regionCoord, regionName }) {

    const mapRef = useRef();

    function handleFlyToClick() {
      // This don't work
      // const map = mapRef.current.leafletElement 
      // map.flyTo(regionCoord, zoom)
    }

 return (   
        <React.Fragment>
            <Grid container >
                <Grid item xs={10}>
                    {regionCoord amp;amp; <MapContainer
                        ref={mapRef}                     
                        center={[50,50]} 
                        zoom={zoom}                    
                        >
                        <TileLayer
                            attribution='amp;copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                        />            
   
                        <Marker position={regionCoord}>
                          <Popup>{regionName}</Popup>
                        </Marker>        
                    </MapContainer>}                               
                </Grid>
                <Grid item xs={2}>
                    <button onClick={handleFlyToClick}>Fly To</button>
                </Grid>
            </Grid>
        </React.Fragment>  
    )
    
}

export default Map
 

Я использую react-leaflet v3

Ответ №1:

Вам нужно использовать компонент, который будет включать вашу кнопку внутри. Чтобы получить экземпляр карты, используйте whenCreated prop of MapContainer . Я думаю mapRef , что это больше не действует в последней версии.

MapContainer:

  const [map, setMap] = useState(null);

 <MapContainer
      center={[50, 50]}
      zoom={zoom}
      style={{ height: "90vh" }}
      whenCreated={setMap}
  >
...

</MapContainer>
<FlyToButton />  // use the button here outside of the MapContainer

....
 

Создайте компонент с кнопкой и ее событием

 function FlyToButton() {
  const onClick = () => map.flyTo(regionCoord, zoom);
    
  return <button onClick={onClick}>Add marker on click</button>;
}
 

ДЕМОНСТРАЦИЯ

Комментарии:

1. Изо всех сил пытаясь найти, как получить instace карты (whenCreated={setMap}) спасла мне жизнь. Спасибо

2. Жаль, что это не было в документации!

3. whenCreated, похоже, не существует в react-листовке 4.x

4. Этот ответ был для react-leaflet v.3.x. Это четко указано в вопросе.

5. @kboul разве вы не посчитали бы это дубликатом, если бы кто-то опубликовал тот же точный вопрос для 4.x?

Ответ №2:

вам нужно получить доступ к элементу карты (из компонента карты, который является контейнером, а не MapContainer), это очень простой пример:

 export default function MapComponent() {
    const [mapCenter,setMapCenter] = useState([13.1538432,30.2154278])
    let [zoom,setZoomLevel] = useState(15)
    let [tile,setTile] = useState('https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png')
    
    let mapRef = useRef();

    const fly=()=>{
        mapRef.current.leafletElement.flyTo([14,30],15)
    }

    return (
    <>
        <button onClick={fly}>Click</button>
        <Map center={mapCenter} zoom={zoom} ref={mapRef} style={{width:'100%',height:'100%'}}>
            <TileLayer url={tile}/>
        </Map>
    </>  
    )
}
 

Комментарии:

1. я увидел ответ @kboul после того, как опубликовал это, обратите внимание, что я использую react-листовку 2.8.0.

2. Это больше не работает в листовке 3.0. Способ таков, как описано в принятом здесь ответе, используя <MapContainer center={[50, 50]} zoom={zoom} style={{ height: «90vh» }} whenCreated={setMap} >

Ответ №3:

whenCreated больше не существует в версии 4.0, но есть ref :

MapContainer:

 const [map, setMap] = useState<Map>(null);

 <MapContainer
      center={[50, 50]}
      zoom={zoom}
      style={{ height: "90vh" }}
      ref={setMap}
  >
   <div> 
     ... do whatever you want with `map`
   </div
</MapContainer> 
 

Ответ №4:

Работает как для 3.x, так и для 4.x:

Другой метод заключается в использовании useMap перехвата, который существует в 3.x и 4.x. Чтобы использовать его в родительском компоненте, вам просто нужно добавить дочерний компонент, например MapController , ниже.

 const MapController = () => {
  const map = useMap();

  // do something with map, in a useEffect hook, for example.

  return <></>;
};

 <MapContainer
      center={[50, 50]}
      zoom={zoom}
      style={{ height: "90vh" }}
  >
   <MapController />
   <div> 
     ... do whatever you want with `map`
   </div
</MapContainer>