微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在点列表中添加一个点并在地图上重新渲染

如何解决在点列表中添加一个点并在地图上重新渲染

所以基本上我要做的是让用户双击地图并创建一个包含一些信息的新点。当他们点击提交时,应该将点添加到状态(或稍后添加数据库中),然后地图重新呈现正确的信息。这就是我到目前为止所拥有的,我哪里出错了:

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;

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,当我双击地图时会发生这种情况。不知道为什么会这样。任何帮助将不胜感激。

解决方法

现在您正在创建一个 JSX 元素数组,在我看来这使事情变得不必要地复杂。实际上,它比听起来要简单得多。

您想使用弹出窗口存储有关位置的信息。 所以你的数据将是

  1. 纬度
  2. 姓名
  3. 案例状态

您的数据应该是包含上述 3 个属性的对象数组

您甚至可以从示例中的几个虚拟数据开始。位置的初始状态应该类似于下面的位置变量。

function LocationMarkers() {
  const [locations,setLocations] = useState(
    [
      {
        latlng: [43.653226,-79.3831843],name: "point1",caseStatus: "random point1"
      }
    ],{
      latlng: [50.653226,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 调用以保存、编辑或删除数据库中的数据时才需要它。 现在,一旦您在地图上添加了一个点,您就可以点击该点,您就会看到包含信息的弹出窗口,并且可以添加/更改它们

Demo

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。