16

App.js

import { useState } from 'react';

const App = () => {
  // This state is used to the center attribute of MapContainer component
  const [mapCenter, setMapCenter] = useState([34.80746, -40.4796]);
  // This state is used to the zoom attribute of MapContainer component
  const [mapZoom, setMapZoom] = useState(3);

  const onClickHandler = () => {
    setMapCenter([20, 100]);
    setMapZoom(5);
  };

  return (
    <>
      <button onClick={onClickHandler}>Change map's center location</button>
      <Map center={mapCenter} zoom={mapZoom} />
    </>
  );
};

Map.js

import React from 'react';
import './Map.css';
import { MapContainer, TileLayer } from 'react-leaflet';

function Map({ center, zoom }) {
  return (
    <div className="map">
      <MapContainer center={center} zoom={zoom}>
        <TileLayer
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          attribution='&copy; <a 
                href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        />
      </MapContainer>
    </div>
  );
}

export default Map;

Map.css

.map {
  height: 500px;
  background-color: white;
  padding: 1rem;
  border-radius: 20px;
  margin-top: 16px;
  box-shadow: 0 0 8px -4px rgba(0, 0, 0, 0.5);
}

.map .leaflet-container {
  height: 100%;
}

When I clicks button, mapCenter state clearly changes to [20, 100] and mapZoom also changes to 5. But in the Map Component Map does not show new center. but I don't know why. I already checked state's change. Map never respond. Does anyone knows??? Please answer a way to figure it out.

4 Answers 4

41

Except for its children, MapContainer props are immutable: changing them after they have been set a first time will have no effect on the Map instance or its container. The Leaflet Map instance created by the MapContainer element can be accessed by child components using one of the provided hooks or the MapConsumer component.
https://react-leaflet.js.org/docs/api-map

ChangeView.js

function ChangeView({ center, zoom }) {
  const map = useMap();
  map.setView(center, zoom);
  return null;
}

Map.js

function Map({ center, zoom }) {
  return (
    <div className="map">
      <MapContainer center={center} zoom={zoom} scrollWheelZoom={false}>
        <ChangeView center={center} zoom={zoom} /> 
        <TileLayer
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        />
      </MapContainer>
    </div>
  );
}

The react-leaflet documentation uses setCenter in it's useMapEvent example, but this function isn't defined. However in leaflets documentation Methods for modifying map state there is a function setView(center, zoom, options?).

2
  • 1
    It is so helpful. Thank you for your answer. I finally resolved it.
    – 박병찬
    Commented Nov 4, 2020 at 11:52
  • @Banny you can just render something else until you have the center coordinates. E.g. (like a loading animation)
    – JBaczuk
    Commented Aug 6, 2021 at 14:38
6
const Map = ({ center, zoom }) => {
  const [map, setmap] = useState(null);
  if (map) {
    map.flyTo(center);
  }
  return (
    <div className="map">
      <LeafletMap
        center={center}
        zoom={zoom}
        whenCreated={setmap}
        scrollWheelZoom={false}
      >
        <TileLayer
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        ></TileLayer>
      </LeafletMap>
    </div>
  );
};
1
  • 3
    Hi, welcome to Stack Overflow! When answering a question, please include some commentary for the questioner and other readers to understand your solution.
    – MrT
    Commented Apr 16, 2021 at 20:13
3

In your Map compontent for example map.js add this function:

const Recenter = ({lat,lng}) => {
        const map = useMap();
        useEffect(() => {
            map.setView([lat, lng]);
        }, [lat, lng]);
        return null;
    }

And call it inside your MapContainer:

export default function Map(props){

const [position, setPosition] = useState({ lat: 98.699739, lng: 52.338097 }); // set default position

useEffect(()=> {
        if(props.latlng){
            setPosition(props.latlng); // update via props
        }
    }, [props]);

/* other codes */

    <MapContainer center={position} zoom={14} scrollWheelZoom={false}>
       <Recenter lat={position.lat} lng={position.lng} />
    </MapContainer>

And here you can update new position with setPosition and it will automatically recenter map on position update.

1

Instead You can use map-flyto.

flyTo(<LatLng> latlng, <Number> zoom?, <Zoom/pan options> options?)

Working Example

import {
  MapContainer,
  TileLayer,
  useMap,
} from "react-leaflet";

// Used to recenter the map to new coordinates
const MapRecenter= ({ lat, lng, zoomLevel }) => {
  const map = useMap();

  useEffect(() => {
    // Fly to that coordinates and set new zoom level
    map.flyTo([lat, lng], zoomLevel );
  }, [lat, lng]);
  return null;

};

// Render Map Component
function Map() {
 // Set initials
 const center = [30.375321, 69.345116]; 
 const zoom = 4;

  return (
    <div className="map">
      <MapContainer center={center} zoom={zoom}>
        {/* Cusotm Recenterig of Map component */} 
        {/* Pass New Cordinated and ZoomLevel */}       
        <MapRecenter lat={33.6712} lng={35.8277} zoomLevel={6} />
          <TileLayer
            noWrap={false}
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          />
      </MapContainer>
    </div>
  );
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.