繁体   English   中英

如何使用 React 管理 OpenLayers Overlay 生命周期?

[英]How to manage OpenLayers Overlay lifecycle using React?

给定一个使用 OpenLayers 渲染交互式地图的 React 应用程序,我想为显示的功能提供工具提示。 生命周期应如下所示:地图上没有或只有一个工具提示。 如果用户在某个要素的特定距离内单击,工具提示会出现在该要素在地图上的位置附近,如果之前有工具提示,则会被新工具提示替换。 如果用户单击附近没有要素的地图部分,则先前的工具提示将被破坏。

我已经尝试了多种实现这种逻辑的方法,但最后一个让我无法成功的逻辑缺陷是当 React 想要卸载一个工具提示组件时,它无法找到它,因为 OpenLayers 将它移到了它自己的ol-overlay-container容器中.

正如在对类似问题的回答中所建议的那样,一个可能的解决方案是使用 react 的createPortal将工具提示直接呈现到 openlayers 无论如何都会将其复制到的 DOM 位置。 这个问题似乎是 openlayers 仍然包裹了元素,使得在卸载时无法做出反应来移除它。

到目前为止,这是我的弹出/工具提示组件代码:


import { Overlay } from "ol"
import { createRef, useEffect, useRef, useState } from "react"
import { createPortal } from "react-dom"
import useMap from "../../Hook/useMap"

const Popup = ({ feature, position, ...props }) => {
  const { map } = useMap()  // custom map context
  const overlay = useRef()
  const [domReady, setDomReady] = useState(false)
  const overlayContainer = useRef()
  const overlayContent = createRef()

  useEffect(() => {
    setDomReady(true)
    overlayContainer.current = document.getElementsByClassName(
      "ol-overlay-container ol-selectable"
    )[0]
    return () => {
      setDomReady(false)
    }
  }, [])

  useEffect(() => {
    if (domReady && overlayContainer.current) {
      overlay.current = new Overlay({
        element: overlayContainer.current,
        id: "popup",
      })
      if (position) {
        overlay.current.setPosition(position)
      }
      map.addOverlay(overlay.current)
      return () => {
        map.removeOverlay(overlay.current)
      }
    }
  }, [domReady, feature, position])

  return domReady
    ? createPortal(
        <div className="test-overlay" ref={overlayContent}>
          {props.children}
        </div>,
        overlayContainer.current
      )
    : null
}

export default Popup

这就要求在应用程序的整个生命周期中都存在类名为ol-overlay-container ol-selectable 默认情况下,它似乎只有在将叠加层添加到地图后才会创建。 因此,我用一个空覆盖层初始化我的地图,其元素是我在 index.html 中创建的一个div


const map = new OlMap({
  overlays: [
    new Overlay({
      id: "preserveOverlayContainer",
      element: document.getElementById("map-overlay"),
      position: [0, 0],
    }),
  ],
  ...
})

有没有办法让工具提示包含由 React 管理的内容,但使用 openlayers 渲染到地图中?

与此同时,我想出了一个 hacky,但看似可行的解决方案:

return () => {
        map.removeOverlay(overlay.current)
        const outer = document.createElement("div")
        outer.id = "map-overlay-outer"

        document.body.appendChild(outer)

        overlayContainer.current = document.getElementById("map-overlay-outer")
      }

在第二个useEffect的清理函数中, removeOverlay()方法调用将之前呈现的工具提示从 DOM 中完全移除,因此我们只需重新创建它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM