可以在 .setHTML 或 .setDOMContent 中的 mapboxgl.Popup() 中渲染 react 组件吗?

IT技术 javascript reactjs react-redux mapbox mapbox-gl
2021-05-19 07:42:09

我想知道是否可以在 mapboxgl.Popup() 中渲染一个 react 组件。像这样的东西:

    componentDidMount() {
            new mapboxgl.Popup()
            .setLngLat(coordinates)
            .setHTML(`<div>${<MapPopup />}<p>${moreText}</p></div>`)
            //.setDOMContent(`${<MapPopup />}`) ?????
            .addTo(this.props.mapboxMap)
    })

还是应该使用 ReactDOM.render 来完成?

ReactDOM.render(<MapPopup />, document.getElementById('root'))

该项目将在弹出窗口中具有连接到 redux 存储的按钮和输入。

感谢您提供任何意见!

4个回答

这有效:

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);
}

(我已经使用 typescript 来说明类型,但您可以将它们留给纯 js。)将其用作

addPopup(<h1>Losers of 1966 World Cup</h1>, 52.5, 13.4);

你可以尝试实现 React 组件:

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>
    );
};

经过一些测试,我意识到Popup组件没有在地图上正确渲染。而且卸载组件也不成功。这就是为什么有两个 div 作为回报。但是,它可能只发生在我的环境中。

有关其他信息,请参阅https://docs.mapbox.com/mapbox-gl-js/api/#popupmapboxPopupProps

useEffect 依赖项确保 MapboxPopup 每次列表中的某些内容更改时都会重新创建并使用 return popup.remove;

我也一直在与这个作斗争。我发现的一种解决方案是使用 ReactDOM.render()。我创建了一个空的弹出窗口,然后使用 mapboxgl 生成的容器来呈现我的 React 组件。

    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')
          );
        }
      });
const mapCardNode = document.createElement("div");

mapCardNode.className = "css-class-name";

ReactDOM.render( 
  <YourReactPopupComponent / > ,
  mapCardNode
);

//if you have a popup then we remove it from the map
if (popupMarker.current) popupMarker.current.remove();

popupBox.current = new mapboxgl.Popup({
        closeOnClick: false,
        anchor: "center",
        maxWidth: "240px",
    })
    .setLngLat(coordinates)
    .setDOMContent(mapCardNode)
    .addTo(map);