使用 geojson pointToLayer 函数时需要正确的方法在 Leaflet 弹出窗口中呈现 jsx 组件
Need proper way to render jsx component inside Leaflet popup when using geojson pointToLayer function
您好,有没有什么方法可以将 jsx 组件传递给 bindPopup 函数,这样我就可以在单击按钮时推送 redux 命令?
pointToLayer={(
geoJsonPoint: Feature<Point, DeviceProperties>,
latlng,
) => {
const marker = L.marker(latlng);
marker.setIcon(
markerIcon({ variant: geoJsonPoint.properties.relation }),
);
const sddds = (
<div className="font-quicksand">
<h2>{geoJsonPoint.properties.id}</h2>
<h2>{geoJsonPoint.properties.name}</h2>
<p>{geoJsonPoint.properties.description}</p>
<p>{geoJsonPoint.properties.ownerId}</p>
<a
onClick={() => {
dispatch(setDevice(geoJsonPoint.properties));
}}
>
Open device details
</a>
</div>
);
marker.bindPopup(renderToString(sddds));
return marker;
}}
我知道我可以使用 React 传单组件,但那样我就无法将道具传递到每个标记选项(我的意思是标记作为图层)。
所以这已经讨论了一下。 react-leaflet repo 中有 an issue 讨论这个,其结论是在 bindPopup
方法中简单地使用 vanilla JS 来创建你的弹出窗口。我根本不喜欢这种解决方案,尤其是当您尝试在弹出窗口中使用非常面向反应的事件处理程序(如反应-redux 操作)时。
当您在代码中使用 React 的 renderToString
方法时,您可能已经阅读了 问题。但是正如您可能已经发现的那样,这不会保留您的 JSX 可能包含的任何交互性或 JS。那里的回答者提出了使用模式而不是弹出窗口的想法,但这并不能完全回答你的问题,也不能真正在基于点层 geojson 的弹出窗口中使用 JSX。
最终,您将无法从 pointToLayer
交互功能中 return JSX。我认为这将是 react-leaflet 目前没有实现的一个很好的特性。在 pointToLayer
函数的闭包中,没有好的方法可以直接编写功能齐全的 JSX。
我玩了一会儿,尝试利用 pointToLayer
并将每次迭代的 feature
保存到状态,然后用 Popup
渲染 Marker
从那开始,但它让我思考 - 为什么要打扰?完全放弃 GeoJSON
组件,直接从 JSON 对象渲染 Marker
s 和 Popup
s。像这样:
{myGeoJson.features.map((feature, index) => {
return (
<Marker
key={index}
position={L.latLng(feature.geometry.coordinates.reverse())}
>
<Popup>
<button
onClick={() => { yourReduxAction() }}
>
Click meeee
</button>
</Popup>
</Marker>
);
})}
Working sandbox
在这种情况下,您需要用 Popups
手动将 GeoJSON 转换为 Marker
s从 JSX (<GeoJSON />
) 到 vanilla JS (pointToLayer
) 回到 JSX (<Popup />
).
这是我想到的两个解决方案,如果有人遇到同样的问题,我想与大家分享。
我使用 leaflet-react Popup 组件的问题是,当我只映射 geojson 对象时,它不会将 geojson 属性传递给标记层,因为 react-leaflet Marker 没有像 geojson 层那样的 api 功能,我需要通过地图其他部分的标记层访问这些属性。
解决方案 1:
在 pointToLayer 方法中使用 ReactDOM.render(),React 将显示有关纯函数的警告,但它会起作用。您只是不应该渲染导入的组件,因为它会抱怨存储和 redux 提供程序,而是将组件代码粘贴到渲染中。如果您想避免警告,请创建另一个函数/挂钩并将其 useEffect() 中的代码渲染到容器(div 或其他内容)。
示例如下:
const popup = L.popup();
const marker = L.marker(latlng);
const container = L.DomUtil.create('div');
render(
<div>
<h2>{props.id}</h2>
<h2>{props.name}</h2>
<p>{props.description}</p>
<p>{props.ownerId}</p>
<a onClick={() => dispatch(setDevice(geoJsonPoint.properties))}></a>
</div>,
container,
);
popup.setContent(container);
marker.bindPopup(popup);
return marker;
带有自定义挂钩/函数:
const useRenderPopup = (props) => {
const container = L.DomUtil('div');
const dispatch = useAppDispatch()
useEffect(() => {
render(
<div>
<h2>{props.id}</h2>
<h2>{props.name}</h2>
<p>{props.description}</p>
<p>{props.ownerId}</p>
<a onClick={() => dispatch(setDevice(props.geoJsonPoint.properties))}></a>
</div>,
container,
);
},[])
return container;
}
然后像popup.setContent(useRenderPopup(someprop))那样调用这个函数,这样就不会出现警告了。
解决方案 2:
使用 renderToString() 和其他需要触发 redux update 附加事件侦听器的东西渲染所有静态内容。
const popup = L.popup();
const marker = L.marker(latlng);
const link = L.DomUtil.create('a');
const container = L.DomUtil.create('div');
const content = <DeviceSummary {...geoJsonPoint.properties} />;
marker.setIcon(markerIcon({ variant: geoJsonPoint.properties.relation }));
link.addEventListener('click', () =>
dispatch(setDevice(geoJsonPoint.properties)),
);
link.innerHTML = 'Show device details';
container.innerHTML = renderToString(content);
container.appendChild(link);
popup.setContent(container);
marker.bindPopup(popup);
return marker;
这里的 DeviceSummary 组件是静态的,所以我将它呈现为一个字符串,然后附加 link 并将 redux 回调添加为它的事件侦听器。
(除自定义函数示例外的两种解决方案都进入 geoJSON 层内的 pointToLatyer 方法)
您好,有没有什么方法可以将 jsx 组件传递给 bindPopup 函数,这样我就可以在单击按钮时推送 redux 命令?
pointToLayer={(
geoJsonPoint: Feature<Point, DeviceProperties>,
latlng,
) => {
const marker = L.marker(latlng);
marker.setIcon(
markerIcon({ variant: geoJsonPoint.properties.relation }),
);
const sddds = (
<div className="font-quicksand">
<h2>{geoJsonPoint.properties.id}</h2>
<h2>{geoJsonPoint.properties.name}</h2>
<p>{geoJsonPoint.properties.description}</p>
<p>{geoJsonPoint.properties.ownerId}</p>
<a
onClick={() => {
dispatch(setDevice(geoJsonPoint.properties));
}}
>
Open device details
</a>
</div>
);
marker.bindPopup(renderToString(sddds));
return marker;
}}
我知道我可以使用 React 传单组件,但那样我就无法将道具传递到每个标记选项(我的意思是标记作为图层)。
所以这已经讨论了一下。 react-leaflet repo 中有 an issue 讨论这个,其结论是在 bindPopup
方法中简单地使用 vanilla JS 来创建你的弹出窗口。我根本不喜欢这种解决方案,尤其是当您尝试在弹出窗口中使用非常面向反应的事件处理程序(如反应-redux 操作)时。
当您在代码中使用 React 的 renderToString
方法时,您可能已经阅读了
最终,您将无法从 pointToLayer
交互功能中 return JSX。我认为这将是 react-leaflet 目前没有实现的一个很好的特性。在 pointToLayer
函数的闭包中,没有好的方法可以直接编写功能齐全的 JSX。
我玩了一会儿,尝试利用 pointToLayer
并将每次迭代的 feature
保存到状态,然后用 Popup
渲染 Marker
从那开始,但它让我思考 - 为什么要打扰?完全放弃 GeoJSON
组件,直接从 JSON 对象渲染 Marker
s 和 Popup
s。像这样:
{myGeoJson.features.map((feature, index) => {
return (
<Marker
key={index}
position={L.latLng(feature.geometry.coordinates.reverse())}
>
<Popup>
<button
onClick={() => { yourReduxAction() }}
>
Click meeee
</button>
</Popup>
</Marker>
);
})}
Working sandbox
在这种情况下,您需要用 Popups
手动将 GeoJSON 转换为 Marker
s从 JSX (<GeoJSON />
) 到 vanilla JS (pointToLayer
) 回到 JSX (<Popup />
).
这是我想到的两个解决方案,如果有人遇到同样的问题,我想与大家分享。
我使用 leaflet-react Popup 组件的问题是,当我只映射 geojson 对象时,它不会将 geojson 属性传递给标记层,因为 react-leaflet Marker 没有像 geojson 层那样的 api 功能,我需要通过地图其他部分的标记层访问这些属性。
解决方案 1:
在 pointToLayer 方法中使用 ReactDOM.render(),React 将显示有关纯函数的警告,但它会起作用。您只是不应该渲染导入的组件,因为它会抱怨存储和 redux 提供程序,而是将组件代码粘贴到渲染中。如果您想避免警告,请创建另一个函数/挂钩并将其 useEffect() 中的代码渲染到容器(div 或其他内容)。
示例如下:
const popup = L.popup();
const marker = L.marker(latlng);
const container = L.DomUtil.create('div');
render(
<div>
<h2>{props.id}</h2>
<h2>{props.name}</h2>
<p>{props.description}</p>
<p>{props.ownerId}</p>
<a onClick={() => dispatch(setDevice(geoJsonPoint.properties))}></a>
</div>,
container,
);
popup.setContent(container);
marker.bindPopup(popup);
return marker;
带有自定义挂钩/函数:
const useRenderPopup = (props) => {
const container = L.DomUtil('div');
const dispatch = useAppDispatch()
useEffect(() => {
render(
<div>
<h2>{props.id}</h2>
<h2>{props.name}</h2>
<p>{props.description}</p>
<p>{props.ownerId}</p>
<a onClick={() => dispatch(setDevice(props.geoJsonPoint.properties))}></a>
</div>,
container,
);
},[])
return container;
}
然后像popup.setContent(useRenderPopup(someprop))那样调用这个函数,这样就不会出现警告了。
解决方案 2:
使用 renderToString() 和其他需要触发 redux update 附加事件侦听器的东西渲染所有静态内容。
const popup = L.popup();
const marker = L.marker(latlng);
const link = L.DomUtil.create('a');
const container = L.DomUtil.create('div');
const content = <DeviceSummary {...geoJsonPoint.properties} />;
marker.setIcon(markerIcon({ variant: geoJsonPoint.properties.relation }));
link.addEventListener('click', () =>
dispatch(setDevice(geoJsonPoint.properties)),
);
link.innerHTML = 'Show device details';
container.innerHTML = renderToString(content);
container.appendChild(link);
popup.setContent(container);
marker.bindPopup(popup);
return marker;
这里的 DeviceSummary 组件是静态的,所以我将它呈现为一个字符串,然后附加 link 并将 redux 回调添加为它的事件侦听器。
(除自定义函数示例外的两种解决方案都进入 geoJSON 层内的 pointToLatyer 方法)