1

I´ve been reading the changelog in v3 and I see several changes.

The Map component is replaced by MapContainer, behaving differently, among other things that props are immutable I would like to create a MapContainer and be able to update the width and height dynamically, for example when I user minimize the window or when a component changes of size.

How can I do this without kill MapContainer and creating other new ??

 <MapContainer whenCreated={...} style={{width:xxx, height:yyy}}

4 Answers 4

2

Use map's "invalidateSize" function:

const { height } = useSize(container);
useEffect(() => {
  if (map != null) {
    map.invalidateSize();
  }
}, [map, height]);

You can put this in a child of the map as explained in the other anser, or in the parent with map as a ref on MapContainer, it works either way.

MapContainer only needs static style:

width: 100%;
height: 100%;

No issue anymore (finally)

0

Combining the answers above, you can use a custom hook to get the size of your container

import { useState, useEffect } from "react"

export default function useSize(ref) {
  const [size, setSize] = useState({})

  useEffect(() => {
    if (ref.current == null) return
    const observer = new ResizeObserver(([entry]) => setSize(entry.contentRect))
    observer.observe(ref.current)
    return () => observer.disconnect()
  }, [])

  return size
}

Create another component to fetch new tiles every time the map is resized

import { useMap } from "react-leaflet";

const ResizeMap = ({ containerRef }) => {
  const map = useMap();
  const { width, height } = useSize(containerRef);

  useEffect(() => {
    if (map) {
      setTimeout(() => {
        map.invalidateSize();
      }, 100);
    }
  }, [height, width]);

  return null;
};

Then in your map you can assign a ref to your container and pass that ref to your ResizeMap component

const containerRef = useRef(null)

<div ref={containerRef} className="container">
  <MapContainer
    {...props}
    style={{ width: "100%", height: "100%" }}
  > 
  <ResizeMap containerRef = {containerRef} />
   ...
  </MapContainer >
<div>

This way you can handle the size of your map with any styles defined in the .container class

0

Hooman's answer worked for me, but when changing width the lines and polygons were not rendering well, so the updated solution for me to change height and width was this:


import { MapContainer, TileLayer, useMap, Polyline } from 'react-leaflet'


export const GeographicView = (props) => {
    const SetHeightOnChange = ({ height }) => {
        const map = useMap();
        useEffect(() => {
          if (map != null) {
            map.invalidateSize();
          }
        }, [map, height]);
        const mapContainer = map.getContainer();
        mapContainer.style.cssText = `height: ${height}; width: 100%; position: relative;`;

        return null;
    }

    return (
          <MapContainer
            style={{ height: props.height || "80vh", width: "100%" }}
            center={props.centroid}
            zoom={8}
            scrollWheelZoom={false}
          >
            <SetHeightOnChange height={props.height || "80vh"} />
            <TileLayer
              attribution="Google Maps Satellite"
              url="https://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}"
            />
            <Polyline
              key={index}
              positions={props.shape.vertices}
              pathOptions={{
                color: legend.find(item => item.value === props.shape.legend)?.color || "blue",
              }}
            />
      </MapContainer>
    )
}
New contributor
Esnyan is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
-1

I faced the same problem after I migrated to react-leaflet v3.x

So, I made a trick by using react-leaflet useMap hook and had a successful attempt to the resize the map based on its container (Whatever it is as well as the window).

So my Map Container code looks like this:

  function SetHeightOnChange({ height }) {
    const map = useMap();

    const mapContainer = map.getContainer();
    mapContainer.style.cssText = `height: ${height}px; width: 100%; position: relative;`;

    return null;
  }

  return (
    <MapContainer
      center={center}
      zoom={13}
      style={{
        height: height + "px",
        width: "100%",
      }}
    >
      <TileLayer
        attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      <CircleMarker center={position}>
        <Popup>
          A pretty CSS3 popup. <br /> Easily customizable.
        </Popup>
      </CircleMarker>
      <SetHeightOnChange height={height} />
    </MapContainer>
  );

Notice that: for the map width, all you need is to set it to 100%.

Please also notice the child component inside MapContainer which I named it SetHeightOnChange. (Make sure to place that child component after Marker tag).

Now whenever you trigger an update on height value after any resizing changes, your map size will change accordingly.

1
  • 1
    Could you please include how you manage the height variable?
    – Nad Hr
    Commented Sep 11, 2023 at 15:19

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