I am wondering if it is possible to render a react component within a mapboxgl.Popup(). Something like this:
componentDidMount() {
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(`<div>${<MapPopup />}<p>${moreText}</p></div>`)
//.setDOMContent(`${<MapPopup />}`) ?????
.addTo(this.props.mapboxMap)
})
Or should this be done using ReactDOM.render?
ReactDOM.render(<MapPopup />, document.getElementById('root'))
This project will have buttons and inputs in the popup that connect to a redux store.
Thanks for any input!
This works:
addPopup(el: JSX.Element, lat: number, lng: number) {
const placeholder = document.createElement('div');
ReactDOM.render(el, placeholder);
const marker = new MapboxGl.Popup()
.setDOMContent(placeholder)
.setLngLat({lng: lng, lat: lat})
.addTo(map);
}
(Where I've used typescript to illustrate types, but you can just leave these out for pure js.) Use it as
addPopup(<h1>Losers of 1966 World Cup</h1>, 52.5, 13.4);
You can try to implement React component:
export const Popup = ({ children, latitude, longitude, ...mapboxPopupProps }) => {
// this is a mapbox map instance, you can pass it via props
const { map } = useContext(MapboxContext);
const popupRef = useRef();
useEffect(() => {
const popup = new MapboxPopup(mapboxPopupProps)
.setLngLat([longitude, latitude])
.setDOMContent(popupRef.current)
.addTo(map);
return popup.remove;
}, [children, mapboxPopupProps, longitude, latitude]);
return (
/**
* This component has to have 2 divs.
* Because if you remove outter div, React has some difficulties
* with unmounting this component.
* Also `display: none` is solving that map does not jump when hovering
* ¯\_(ツ)_/¯
*/
<div style={{ display: 'none' }}>
<div ref={popupRef}>
{children}
</div>
</div>
);
};
After some testing, I have realized that Popup
component was not rendering properly on the map. And also unmounting the component was unsuccessful. That is why there are two divs in return. However, it may happen only in my environment.
See https://docs.mapbox.com/mapbox-gl-js/api/#popup for additional mapboxPopupProps
useEffect
dependencies make sure that MapboxPopup gets re-created every time something of that list changes & cleaning up the previous popup instance with return popup.remove;
I've been battling with this as well. One solution I found was using ReactDOM.render(). I created an empty popup then use the container generated by mapboxgl to render my React component.
marker.setPopup(new mapboxgl.Popup({ offset: 18 }).setHTML(''));
markerEl.addEventListener('mouseenter', () => {
markerEl.classList.add('enlarge');
if (!marker.getPopup().isOpen()) {
marker.getPopup().addTo(this.getMap());
ReactDOM.render(
component,
document.querySelector('.mapboxgl-popup-content')
);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With