所以基本上我要做的是让用户双击地图并创建一个包含一些信息的新点。当他们点击提交时,应该将点添加到状态(或稍后添加到数据库中),然后地图重新呈现正确的信息。这就是我到目前为止所拥有的,我哪里出错了:
App.js
import './App.css';
import * as React from "react";
import { ChakraProvider } from "@chakra-ui/react";
import { MapContainer, TileLayer, Marker, Popup, useMapEvents, useMap } from 'react-leaflet'
import 'leaflet/dist/leaflet.css'
import * as L from 'leaflet';
import SearchBar from './SearchBar';
import CovidPoint from './CovidPoint';
import LocationMarkers from './LocationMarkers';
class App extends React.Component {
constructor(props){
super(props)
this.state = {
map: null,
points: [<CovidPoint
position={[43.653226, -79.3831843]}
name="point1"
information="random point"
input = {false}
></CovidPoint>,
<CovidPoint
position={[50.653226, -79.3831843]}
name="point2"
information="random point"
input = {true}
></CovidPoint>]
}
}
changePos = (pos, zoom) => {
const {map} = this.state;
if (map) map.flyTo(pos, zoom);
}
fetchPoints = (newPoints) => {
this.setState({points: newPoints})
this.state.points.length > 0 && this.state.points.map(
(point) => {
return point
}
)
}
render() {
return (
<div className="App">
<div id="title">
<h1>CovidStopSpots</h1>
<p>A responsive tracker for Covid-19.</p>
</div>
<div id="map">
<MapContainer
id="1"
center={[43.653226, -79.3831843]}
zoom={13}
scrollWheelZoom={false}
whenCreated={(map) => this.setState({ map })}
style={{ height: "100vh " }}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{this.state.points.length > 0 && this.state.points.map(
(point) => {
return point
}) }
{/* <CovidPoint
position={[43.653226, -79.3831843]}
name="point1"
information="random point"
></CovidPoint>
<CovidPoint
position={[50.653226, -79.3831843]}
name="point2"
information="random point"
></CovidPoint> */}
<LocationMarkers points={this.state.points} fetchPoints={this.fetchPoints}></LocationMarkers>
</MapContainer>
</div>
</div>
);
}
}
export default App;
LocationMarkers.js
import { useState } from "react";
import { useMapEvents } from "react-leaflet";
import CovidPoint from "./CovidPoint";
function LocationMarkers(props) {
const [position, setPosition] = useState([]);
useMapEvents({
dblclick(ev) {
console.log("double clicked");
const { lat, lng } = ev.latlng;
setPosition([lat, lng]);
const newPoints = [...props.points];
console.log(newPoints);
newPoints.push(<CovidPoint position={position} input={true}></CovidPoint>);
props.fetchPoints(newPoints);
}
});
return null;
}
export default LocationMarkers;
CovidPoint.js
import React from "react";
import { Marker, Popup } from "react-leaflet";
import L from "leaflet";
import { ChakraProvider, Button, Input} from "@chakra-ui/react";
class CovidPoint extends React.Component {
constructor(props) {
super(props);
this.state = {
position: this.props.position,
name: this.props.name,
input: this.props.input,
information: this.props.information,
key: this.props.key
};
}
pushPoint(name, info){
//push to the database
console.log("pushed to db", name, info)
this.setState({input: false})
}
GetType = (icon) => {
if (this.state.input === true){
return (
console.log("input point"),
<Marker position={this.state.position} icon={icon}>
<Popup>
Name: <Input size="sm" variant="outline" placeholder="Name" onChange={ev => {this.setState({name: ev.target.value})}}/> <br />
Case Status: <Input size="sm" variant="outline" placeholder="Case Status" onChange={ev => {this.setState({information: ev.target.value})}}/> <br />
<Button size = "xs" variant="solid" colorScheme="twitter" onClick={ev => {
if (this.state.name != "" && this.state.information != ""){
this.pushPoint(this.state.name, this.state.information);
}}}> Submit </Button>
</Popup>
</Marker>
)
}
return (
console.log("normal point"),
<Marker position={this.props.position} icon={icon}>
<Popup>
Name: {this.state.name} <br />
position: {this.state.position} <br />
Case Status: {this.state.information}
</Popup>
</Marker>
)
}
render() {
const covidIcon = L.icon({
iconUrl:
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Redpoint.svg/768px-Redpoint.svg.png",
iconSize: [30, 30], // size of the icon
iconAnchor: [0, 0], // point of the icon which will correspond to marker's location
popupAnchor: [0, 0] // point from which the popup should open relative to the iconAnchor
});
return (
<ChakraProvider>
<div>
{this.GetType(covidIcon)}
</div>
</ChakraProvider>
);
}
}
export default CovidPoint;
此外,我得到的当前错误是 TypeError: Cannot read property 'lat' of null
,当我双击地图时会发生这种情况。不知道为什么会这样。任何帮助将不胜感激。
答案 0 :(得分:1)
现在您正在创建一个 JSX 元素数组,在我看来这使事情变得不必要地复杂。实际上,它比听起来要简单得多。
您想使用弹出窗口存储有关位置的信息。 所以你的数据将是
您的数据应该是包含上述 3 个属性的对象数组
您甚至可以从示例中的几个虚拟数据开始。位置的初始状态应该类似于下面的位置变量。
function LocationMarkers() {
const [locations, setLocations] = useState(
[
{
latlng: [43.653226, -79.3831843],
name: "point1",
caseStatus: "random point1"
}
],
{
latlng: [50.653226, -79.3831843],
name: "point2",
caseStatus: "random point2"
}
);
useMapEvents({
dblclick(ev) {
const { lat, lng } = ev.latlng;
const newLocations = [...locations];
newLocations.push({ latlng: [lat, lng], name: "", caseStatus: "" });
setLocations(newLocations);
}
});
return <CovidPoint locations={locations} setLocations={setLocations} />;
}
每次您在地图上添加一个点时,您都会向位置数组推送一个新的位置对象,其中包含开头的坐标并托管您稍后要添加的其他属性。
将位置和 setLocations 作为道具传递给 CovidPoint,以便能够使用位置索引从那里添加、编辑名称和案例状态。
那么在你的 CovidPoint comp 中你不需要任何状态。
const { locations, setLocations } = this.props;
return (
locations.length > 0 &&
locations.map(({ latlng, name, caseStatus }, index) => (
<Marker position={latlng} icon={covidIcon} key={index}>
<Popup>
Name:
<input
placeholder="Name"
value={name}
onChange={(e) => {
const newLocations = [...locations];
const newLocationObj = { ...newLocations[index] };
newLocationObj.name = e.target.value;
newLocations[index] = newLocationObj;
setLocations(newLocations);
}}
/>
<br />
<br />
Case Status:
<input
value={caseStatus}
placeholder="Case Status"
onChange={(e) => {
const newLocations = [...locations];
const newLocationObj = { ...newLocations[index] };
newLocationObj.caseStatus = e.target.value;
newLocations[index] = newLocationObj;
setLocations(newLocations);
}}
/>
</Popup>
</Marker>
))
);
您甚至不需要提交按钮就可以在本地更改状态。仅当您想进行 api 调用以保存、编辑或删除数据库中的数据时才需要它。 现在,一旦您在地图上添加了一个点,您就可以点击该点,您就会看到包含信息的弹出窗口,并且可以添加/更改它们