Maksym Popov
Maksym Popov

Reputation: 452

How to open popup in react-leaflet?

I am working on developing a react-leaflet map that has multiple markers. My intention is to make popups open one by one with interval.

So, my markers are rendered by mapping an array and returning component

arr.map((item, i) => <CustomMarker isActive={isActive} data={item} key={i} />)

isActive is a value that says should popup be active.

<CustomMarker /> looks like this:

const CustomMarker = ({isActive, data}) => {
  return (
    <Marker position={data.position}>
      <Popup>
        <a href={data.url}>Go to this website</a>
      </Popup>
    </Marker>
  )
}

I tried several things but none do work for me.

  1. Implement through eventHandlers
  2. Create custom icon using L.divIcon() and write HTML with custom popup. However, popup was unclickable as it was a part of markers icon.

How can use isActive value to open popup?

Upvotes: 4

Views: 13700

Answers (1)

Seth Lutske
Seth Lutske

Reputation: 10686

You can do this by getting a ref to the react-leaflet Popup component, and once that ref is ready, using it to call the openOn method of an L.popup.

First you need a ref to the map that can be passed to each CustomMarker:

const Map = (props) => {
  const [map, setMap] = useState();

  return (
    <MapContainer
      whenCreated={setMap}
      {...otherProps}
    >
      <CustomMarker
        map={map}
        data={{
          position: [20.27, -157]
        }}
      />
      <CustomMarker
        map={map}
        data={{
          position: [20.27, -156]
        }}
        isActive
      />
    </MapContainer>
  );
};

As you can see, each CustomMarker takes the map reference as a prop. Then within the CustomMarker, you need to get a ref to the Popup component. Note that a ref will not be available on mount. You need to wait for the ref to be available. But because useEffect's dont cause rerenders when a ref changes value, you can let the component know the ref is ready by setting a state variable in a ref callback:

const CustomMarker = ({ isActive, data, map }) => {
  const [refReady, setRefReady] = useState(false);
  let popupRef = useRef();

  useEffect(() => {
    if (refReady && isActive) {
      popupRef.openOn(map);
    }
  }, [isActive, refReady, map]);

  return (
    <Marker position={data.position}>
      <Popup
        ref={(r) => {
          popupRef = r;
          setRefReady(true);
        }}
      >
        Yupperz
      </Popup>
    </Marker>
  );
};

The ref is only available once the component mounts. In the ref prop, first we set the ref to our useRef value, and then we change the state variable refReady to be true. The useEffect fires when this value changes. The if statement assures that the ref indeed exists. If the ref is ready, and isActive is true, the we call L.popup.openOn(map), and your popup is open on mount.

Working codesandbox

Or, if you don't want to bother with all that, ths functionality (and more!) is built in to a react-leaflet-editable-popup.

Upvotes: 6

Related Questions