const IconGen = ({ incomingData }) => {
const [dataMap, setDataMap] = useState({});
const dataMapTemp = {};
incomingData.BandData.forEach((each) => {
dataMapTemp[each.AntennaX].list.push(each);
dataMapTemp[each.AntennaX].angle= each.angle;
dataMapTemp[each.AntennaX].sId = each.SID;
});
if (!dataMap[1]) {
setDataMap(dataMapTemp);
}
return (
<div class="container_Sector" >
<div class="circle" style={{backgroundColor : "#c31605"></div>
<div
id = {dataMap && dataMap[1]?.sId }
style={{
rotate: `${dataMap[1]?.angle}deg`,
}}
onClick={() => {
alert("You clicked the sector!");
}
}
>
{dataMap[1]?.list.map((each) => generateSvg(each))}
</div>
<div
style={{
rotate: `${dataMap[2]?.angle}deg`,
}}
>
{dataMap[2]?.list.map((each) => generateSvg(each))}
</div>
<div
style={{
rotate: `${dataMap[3]?.angle}deg`,
}}
>
{dataMap[3]?.list.map((each) => generateSvg(each))}
</div>
</div>
);
};
export default IconGen;
//Parent Component
<MapContainer>
<Marker
key={data.SiteID}
position={[data.Latitude, data.Longitude]}
icon = <IconGen
incomingData={data}
/>
>
</Marker>
</Mapcontainer>
我可以使用
icon={L.divIcon({ className: "custom icon", html: ReactDOMServer.renderToString( <MyComponent/> ) })}
渲染自定义图标。
但是,自定义图标组件中的
onClick
不会触发。由于使用 onClick
渲染 MyComponent,ReactDOMServer.renderToString
无法工作。
我需要自定义组件内的
onClick
事件才能正常运行。
onClick
处理程序不起作用的原因是因为renderToString
意味着组件没有真正安装,从某种意义上说,React没有意识到它是一个持续存在的问题。运行 renderToString
将组件减少到该组件在第一次渲染时的 DOM 外观,并且从调用 renderToString
的点起,没有其他任何东西会改变它。
这里的基本问题是
react-leaflet
库不支持开箱即用。但是,我们可以通过以下方式解决这个问题:
L.divIcon
将虚拟 div 渲染为图标,其中不包含任何内容。我们将为每个标记的 div 分配一个唯一的 ID,稍后会派上用场。Marker
组件 add
事件来检测图标何时实际渲染到 DOM。我们可以将此行为封装在
EnhancedMarker
组件中,以方便使用。
这是概念验证的有效 CodeSandbox。在这个概念证明中,我将两个按钮渲染为标记,它们每个都有有效的单击事件。
以下包括可应用于任何情况的通用代码:
import React, { useState, useId, useMemo } from "react";
import { createPortal } from "react-dom";
import { MapContainer, TileLayer, Marker } from "react-leaflet";
// `EnhancedMarker` has the same API as `Marker`, apart from the `icon` can be a React component.
const EnhancedMarker = ({
eventHandlers,
icon: providedIcon,
...otherProps
}) => {
const [markerRendered, setMarkerRendered] = useState(false);
const id = "marker-" + useId();
const icon = useMemo(
() =>
L.divIcon({
html: `<div id="${id}"></div>`,
}),
[id]
);
return (
<>
<Marker
{...otherProps}
eventHandlers={{
...eventHandlers,
add: (...args) => {
setMarkerRendered(true);
if (eventHandlers?.add) eventHandlers.add(...args);
},
remove: (...args) => {
setMarkerRendered(false);
if (eventHandlers?.remove) eventHandlers.remove(...args);
},
}}
icon={icon}
/>
{markerRendered &&
createPortal(providedIcon, document.getElementById(id))}
</>
);
};
const MarkerIconExample = () => {
return (
<>
<button onClick={() => console.log("button 1 clicked")}>Button 1</button>
<button onClick={() => console.log("button 2 clicked")}>Button 2</button>
</>
);
};
const CENTER = [51.505, -0.091];
const ZOOM = 13;
const App = () => {
return (
<MapContainer center={CENTER} zoom={ZOOM}>
<TileLayer
attribution='&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
<EnhancedMarker position={CENTER} icon={<MarkerIconExample />} />
</MapContainer>
);
};
对于您自己的示例,您应该能够:
EnhancedMarker
组件。<Marker>
的现有用法更改为 <EnhancedMarker>
。<IconGen />
<EnhancedMarker>
属性中使用 icon
。