将 React-Leaflet V3.1.0 与 Express 服务器结合使用。
我的用户请求能够使用以下格式的链接:
https://www.mymap.com/id/:category/:id/:zoom
这会向服务器发送请求以获取它们链接到的标记的纬度/经度坐标,然后将起始位置设置为这些坐标。我已经设法使用 React Router Dom 使这部分工作。现在理想情况下,我希望能够在地图加载时打开此特定标记的弹出窗口。按照我设置查询组件的方式,在生成标记以指示这是感兴趣的标记时能够通过 props 传递布尔值不是问题,我只是不确定如何激活弹出窗口。
我不太熟悉 useRef 以及如何准确地使用它来访问不同的 Leaflet 方法,但我昨天做了一些实验,并且能够得到一些行为,这似乎是朝着正确方向迈出的一步。弹出窗口在初始启动时不会加载,但当我在地图上导航时,其他弹出窗口开始自动打开。话虽这么说,我的地图渲染了数千个标记,并且每个标记超过 1 次渲染并不值得牺牲这个相对小众的功能,除非可以将第二个渲染仅隔离到感兴趣的标记。
我认为这种方法可以让我到达我想要的地方,但我无法启动这个特定的方法: https://leafletjs.com/reference-1.6.0.html#popup-openon
我最终使用了类似于此链接的
openPopup()
:
https://stackblitz.com/edit/react-awtgn6?file=Map.js
但是我只能通过 useEffect + useRef 来实现(上面提到的结果)。
我觉得在将弹出窗口打开状态存储在状态中时我遗漏了一些明显的东西?
基本代码示例:
<Marker
position={[item.lat, item.lon]}
icon={getIcon(item)}
>
<Popup position={[item.lat, item.lon]}>
<PopupContent
item={item}
userSettings={userSettings}
/>
</Popup>
</Marker>
谢谢!
如果目标是打开标记的弹出窗口,则在 url 参数中指定标记的
id
(即 url?id=3
)的情况下,这是可行的。
您需要映射一组标记,每个标记都有一个唯一的 ID。您需要保留引用的数组或对象,并且在映射时,在
ref
属性中,将引用添加到该对象数组中:
const Map = (props) => {
const [done, setDone] = React.useState(false);
const markerRefs = React.useRef({});
return (
<MapContainer {...mapContainerProps}>
{data.map((marker, index) => {
return (
<Marker
position={marker.coord}
ref={(m) => { // <--- add marker refs to ref object here
markerRefs.current[marker.id] = m;
if (index === data.length - 1 && !done) {
setDone(true);
}
}}
>
<Popup>{marker.content}</Popup>
</Marker>
);
})}
</MapContainer>
执行map语句后,您的
markerRefs
将是一个对象,其键是id,其值是底层传单标记对象。
裁判准备好后,您需要采取一些行动。您可以使用 useEffect 来做到这一点。现在请记住,将 ref 放入 useEffect 依赖项数组中并不是一个好主意,因为对 ref 的更新不会触发重新渲染。因此,我创建了状态变量
done
,它一开始为 false,但在地图的最后一次迭代中设置为 true。
现在,我们创建一个 useEffect,它在
done
为 true 时运行,这意味着引用已创建并可用:
useEffect(() => {
let params = new URLSearchParams(document.location.search.substring(1));
let id = params.get("id");
if (id && done) {
const markerToOpen = markerRefs.current[id];
markerToOpen.openPopup();
}
}, [done]);
在这个useEffect中,我们检查url参数来获取id。如果有一个 id,并且映射和引用是
done
,我们将根据标记的 id 获取标记 ref,并对其调用 openPopup()
。
请记住,像codesandbox或stackblitz这样的沙盒类型网站有iframe,并且url参数需要在那里可用。对于该沙箱,您需要将预览弹出到其自己的窗口中,或者使用 iframe 的 url:
您会看到,当您在 url 搜索参数中指定
id
时,该标记的弹出窗口会在安装时打开。 (我没有编写任何代码来检查标记是否存在,因此如果您在该示例中尝试 id=doesnt_exist
,它将中断。您需要添加额外的逻辑来检查这一点)。
将其与react-router和您想要使用的其他url参数集成需要一些额外的工作,但这就是我将如何使用refs和state的组合来通过react到达底层传单组件并完成什么你想要。
就重新渲染而言,需要使用许多标记,请记住,react-leaflet 3 经过优化,不是导致重新渲染,而是深入底层的传单组件并调用它们的方法。您可能需要创建其他状态变量来跟踪以帮助实现这一点。例如,您可能有
const [currentOpenMarker, setCurrentOpenMarker] = useState()
,并在其上放置 usEffect 以进入底层传单地图并调用 map.closePopup()
,然后调用 currentOpenMarker.openPopup()
。
我遇到了同样的问题,它对我有用,谢谢