Javascript 将点添加到点列表并在地图上重新渲染

Javascript 将点添加到点列表并在地图上重新渲染,javascript,reactjs,leaflet,react-leaflet,Javascript,Reactjs,Leaflet,React Leaflet,所以基本上我想做的是让用户双击地图,然后用一些信息创建一个新的点。当他们单击“提交”时,应将该点添加到状态(或更高版本的数据库),然后使用正确的信息重新提交地图。这就是我到目前为止所做的,我错在哪里: App.js import './App.css'; import * as React from "react"; import { ChakraProvider } from "@chakra-ui/react"; import { MapContain

所以基本上我想做的是让用户双击地图,然后用一些信息创建一个新的点。当他们单击“提交”时,应将该点添加到状态(或更高版本的数据库),然后使用正确的信息重新提交地图。这就是我到目前为止所做的,我错在哪里:

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='&copy; <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;
import'/App.css';
从“React”导入*作为React;
从“@chakra ui/react”导入{ChakraProvider}”;
从“react传单”导入{MapContainer,TileLayer,Marker,Popup,useMapEvents,useMap}
导入“传单/目录/传单.css”
从“传单”中输入*作为L;
从“./SearchBar”导入搜索栏;
从“./CovidPoint”导入CovidPoint;
从“/LocationMarkers”导入LocationMarkers;
类应用程序扩展了React.Component{
建造师(道具){
超级(道具)
此.state={
map:null,
点数:[,,
]
}
}
更改位置=(位置,缩放)=>{
const{map}=this.state;
if(map)map.flyTo(pos,缩放);
}
fetchPoints=(newPoints)=>{
this.setState({points:newPoints})
this.state.points.length>0&&this.state.points.map(
(点)=>{
返回点
}
) 
}
render(){
返回(
共变顶点
一种针对新冠病毒-19的响应性跟踪器

this.setState({map})} 样式={{高度:“100vh”} > {this.state.points.length>0&&this.state.points.map( (点)=>{ 返回点 }) } {/* */} ); } } 导出默认应用程序;
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;
从“react”导入{useState};
从“react传单”导入{useMapEvents};
从“/CovidPoint”导入CovidPoint;
功能定位标记(道具){
const[position,setPosition]=useState([]);
useMapEvents({
dblclick(ev){
console.log(“双击”);
常数{lat,lng}=ev.latlng;
设定位置([lat,lng]);
const newPoints=[…props.points];
console.log(newPoints);
newPoints.push();
道具。获取点(newPoints);
}
});
返回null;
}
导出默认位置标记;
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;
从“React”导入React;
从“反应传单”导入{标记,弹出};
从“传单”中输入L;
从“@chakra ui/react”导入{脉轮提供者,按钮,输入};
类CovidPoint扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
位置:this.props.position,
名称:this.props.name,
输入:this.props.input,
信息:this.props.information,
钥匙:这个。道具。钥匙
};
}
推送点(名称、信息){
//推送到数据库
日志(“推送到数据库”,名称,信息)
this.setState({input:false})
}
GetType=(图标)=>{
if(this.state.input==true){
返回(
console.log(“输入点”),
名称:{this.setState({Name:ev.target.value}}}}/>
案例状态:{this.setState({information:ev.target.value}}}/>
{ if(this.state.name!=“”&this.state.information!=“”){ this.pushPoint(this.state.name、this.state.information); }}}>提交 ) } 返回( console.log(“正常点”), 名称:{this.state.Name}
位置:{this.state.position}
案例状态:{this.state.information} ) } render(){ 常数共价键=L.icon({ iconUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Redpoint.svg/768px-Redpoint.svg.png", 图标大小:[30,30],//图标的大小 iconAnchor:[0,0],//将对应于标记位置的图标点 popupAnchor:[0,0]//相对于iconAnchor打开弹出窗口的点 }); 返回( {this.GetType(covidIcon)} ); } } 导出默认共点;

另外,我当前遇到的错误是
TypeError:cannotread属性'lat'为null
,当我双击地图时会发生这种情况。不知道为什么会这样。任何帮助都将不胜感激。

现在您正在创建一个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} />;
    }
    
    函数位置标记(){
    常量[位置,设置位置]=使用状态(
    [
    {
    拉丁语:[43.653226,-79.3831843],
    名称:“点1”,
    案例状态:“随机点1”
    }
    ],
    {
    拉丁语:[50.653226,-79.3831843],
    名称:“点2”,
    案例状态:“随机点2”
    }
    );
    useMapEvents({
    dblclick(ev){
    常数{lat,lng}=ev.latlng;
    const newLocations=[…位置];
    推送({latlng:[lat,lng],名称:,案例状态:});
    设置位置(新位置);
    }
    });
    返回;
    }
    
    • 每次在地图上添加点时,都会将一个新的位置对象推送到位置阵列,该位置对象包含开头的坐标,并承载稍后要添加的其他属性

    • 将位置和设置位置作为道具传递给CovidPoint,以便能够使用位置索引从此处添加、编辑名称和案例状态

    • 那么在你的共点组合中,你不需要任何状态 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> )) );