好的,我正在使用react -传单库将一张地图带到我的页面中,这是我用react和nextjs创建的。我增加了反应传单绘制库的组件,允许用户在地图上绘制功能。
我的目标是在用户完成绘制功能时打开一个弹出窗口。在该弹出窗口中将有一个简单的表单,用户可以在其中输入“名称”和“描述”,当单击“保存”时,将发出一个redux操作,包括其有效载荷名称、描述和绘制功能的geojson。
当用户完成绘图时,我能够打开一个弹出窗口,用一个简单的HTML表单填充它,并且独立于它,并将绘制的特性提取为GeoJSON。我的问题是无法提取输入字段的内容。
这是呈现映射的功能组件:
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css';
import 'leaflet-defaulticon-compatibility';
import 'leaflet-draw/dist/leaflet.draw.css'
import { FeatureGroup, MapContainer, Marker, Popup, TileLayer } from 'react-leaflet'
import { locationsType } from '../../pages/api/starterSet'
import { EditControl } from 'react-leaflet-draw'
import styles from '../../styles/components/popupForm.module.css'
import L from 'leaflet';
import PopupForm from './PopupForm'
import { useDispatch } from 'react-redux';
import { testing } from '../../reduxState/reduxState'
import ReactDOMServer from 'react-dom/server'
interface leafletMapProps {
locations: locationsType
drawnLayersRef: any
}
const LeafletMap = ({ locations, drawnLayersRef }:leafletMapProps) => {
const dispatch = useDispatch()
//creating button and its event listener that dispatches action
const button = L.DomUtil.create('button');
button.innerHTML = 'Save';
button.addEventListener('click', () => {
console.log(
"eventlistener triggered, input content: ",
document.getElementById('popupFormName')?.innerHTML
)
dispatch(testing())
});
//creating popupcontent out of simple html form and adding button
const container = L.DomUtil.create('div');
container.innerHTML = ReactDOMServer.renderToString(<PopupForm/>);
container.appendChild(button);
//creating custom popup and filling it with custom content
const popup = L.popup();
popup.setContent(container);
return (
<>
<MapContainer center={[52.5200, 13.4050]} zoom={13} scrollWheelZoom={true} style={{height: 400, width: "100%"}}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<FeatureGroup ref={drawnLayersRef}>
<EditControl
position="topright"
draw={{
rectangle: false,
circle: true,
circlemarker: false,
polyline: {
showLength: true,
metric: true },
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: 'red', // Color the shape will turn when intersects
message: '<strong>That is a terrible polygon! Draw that again!'
}
}
}}
onCreated={(e) => {
console.log("onCreated!")
console.log("CREATED LAYER", e.layer.toGeoJSON())
e.layer.bindPopup(popup).openPopup();
}}
/>
</FeatureGroup>
</MapContainer>
</>
)
}
export default LeafletMap这是包含html表单的函数组件。
import styles from '../../styles/components/popupForm.module.css'
const PopupForm = (ref: any) => {
return (
<form className={styles.form}>
<input
id='popupFormName'
name='name'
placeholder='name...'
ref={ref}
className={styles.inputField}
/>
<textarea
id='popupFormDescr'
name="description"
placeholder="description (max 300 characters)"
maxLength={300}
className={styles.inputTextarea}
/>
</form>
)
}
export default PopupForm我使用ReactDOM.renderToString方法创建弹出的内容,因为在react-传单中,您很不幸不能在弹出窗口中直接呈现JSX。该解决方案被建议为这里。
我尝试使用getElementByID提取带有普通Javascript的输入字段内容,但是innerHTML属性返回为空。当我console.log HTML元素本身时,我得到
<input id="popupFormName" name="name" placeholder="name..." class="popupForm_inputField__iQuhs">我认为这是元素的初始状态,即执行renderToString方法时所处的状态。因此,在renderToString执行之后,浏览器似乎对这些html元素发生的更改不再敏感,尽管它正确地呈现了它们。
我尝试使用Reacts`s的useRef钩子,方法有两种: 1)在映射组件的级别上创建ref,通过道具将其传递给PopupForm组件,并使用ForwardRef组件将其分配给HTML元素和2)。在这两种情况下,我都能够console.log实际的HTML元素,该元素分配了ref,但是它的value属性也是空的。
我已经考虑过ReactDOM.findDOMNode方法,但是它是遗留的,文档声明它不适用于功能组件。
我正在寻找A)一种在弹出窗口中提取HTML输入元素内容的方法,坚持我对renderToString方法或B的方法)一种将HTML或理想的JSX代码引入弹出式中的替代方法,这是已知的与我的usecase一起工作的方法。
帮助是非常感谢的!
发布于 2022-08-15 11:45:11
好的,我改变了弹出内容的构造方式,开始工作了。现在我不再使用ReactDOM.renderToString方法,而是使用ReactDOM.render方法。
这就是现在的整个组件
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css';
import 'leaflet-defaulticon-compatibility';
import 'leaflet-draw/dist/leaflet.draw.css'
import { FeatureGroup, MapContainer, Marker, Popup, TileLayer } from 'react-leaflet'
import { locationsType } from '../../pages/api/starterSet'
import { EditControl } from 'react-leaflet-draw'
import styles from '../../styles/components/popupForm.module.css'
import L from 'leaflet';
import { useDispatch } from 'react-redux';
import { testing } from '../../reduxState/reduxState'
import * as ReactDOM from 'react-dom/client';
interface leafletMapProps {
locations: locationsType
drawnLayersRef: any
}
const LeafletMap = ({ locations, drawnLayersRef }:leafletMapProps) => {
const dispatch = useDispatch()
const createPopupContent = (geoJsonString: string) => {
return <form
className={styles.form}
onSubmit={(event: React.FormEvent<HTMLFormElement> & { target: HTMLFormElement }) => {
console.log("FORMSUBMIT FUNC TRIGGERD")
event.preventDefault()
const formData = Object.fromEntries(new FormData(event.target));
console.log("FORMDATA: ", formData, "GEOJSON: ", geoJsonString)
dispatch(testing())
}
}
>
<input
id='popupFormName'
name='name'
placeholder='name...'
className={styles.inputField}
/>
<textarea
id='popupFormDescr'
name="description"
placeholder="description (max 300 characters)"
maxLength={300}
className={styles.inputTextarea}
/>
<input
id='submitBtn'
type='submit'
name='Submit!'
/>
</form>
}
const renderPopupForm = (geoJsonString: string) => {
const popup = L.popup();
const container = L.DomUtil.create('div');
popup.setContent(container);
const root = ReactDOM.createRoot(container);
root.render(createPopupContent(geoJsonString));
return popup;
}
return (
<>
<MapContainer center={[52.5200, 13.4050]} zoom={13} scrollWheelZoom={true} style={{height: 400, width: "100%"}}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<FeatureGroup ref={drawnLayersRef}>
<EditControl
position="topright"
draw={{
rectangle: false,
circle: true,
circlemarker: false,
polyline: {
showLength: true,
metric: true },
polygon: {
allowIntersection: false,
drawError: {
color: 'red',
message: '<strong>That is a terrible polygon!'
},
}
}}
onCreated={(e) => {
const geoJsonString = e.layer.toGeoJSON()
e.layer.bindPopup(renderPopupForm(geoJsonString), {
closeButton: false
}).openPopup();
}}
/>
</FeatureGroup>
</MapContainer>
</>
)
}
export default LeafletMap我沿着函数传递GeoJSON字符串,这有点笨重,我通过表单提交均衡器中的“新FormData”提取输入值,这不是惯例。
我试着用usestate重写这两个语句,但是在formsubmit均衡器中调用那些状态将返回空值,不知道为什么,很可能与异步属性有关。
我还尝试用函数组件的导入替换createPopupContent(),但这会引发错误。
到目前为止,我也希望它能正常工作,但是如果有人有改进的建议,他们会非常感激的。
https://stackoverflow.com/questions/73353506
复制相似问题