1

I'm building a leaflet map that dipslay markers. These markers have additional data on them besides lat and long, (keys in this case)

I'm using a custom react component from the react-leaflet repo. I can get multiple markers location, but when I try to retrieve the marker I clicked on and pass it to a child component I get

Cannot read property '# < Object > ' of undefined

I can pass ALL the data , without a problem though.

I get this error when I try to pass the "clicked" marker to the Card and Cartitle components.

What I've tried so far:

Inside the handleToggle function I did:

index = this.props.places[index]

but that is when I get the error above. What am I doing wrong?

P.D. Also, Im able to display ALL the data to the children components

import ...

const markers = [
  {
    key: 'P12345678',
    position: [37.786464, -122.411047],
    children: 'My first popup'
  },
  {
    key: 'M12345678',
    position: [40.689192, -74.044563],
    children: 'My second popup'
   },
];


class Mapper extends Component {
  constructor(props) {
    super(props);

    this.handleToggle = this.handleToggle.bind(this);
    this.handleClose = this.handleClose.bind(this);

    this.state = {
      lat: 29.761993,
      lng: -95.366302,
      zoom: 4,
      open: false,
      places: []
    }
  }

  handleToggle(index) {

    const self = this;

    self.setState({
      open: !this.state.open,
      places: markers
    });

    // index = this.props.places[index]

    console.log(this.state.places)


  }

  handleClose() {
    this.setState({
      open: false
    });
  }


  render() {

    const center = [this.state.lat, this.state.lng];

//Custom Marker Component

    const MyPopupMarker = ({ children, position }) => (

      <Marker
        onClick={this.handleToggle}
        position={position}
        places={this.state.places}
      >
        <Popup>
          <span>{children}</span>
        </Popup>

      </Marker>
    )

    MyPopupMarker.propTypes = {
      // children: MapPropTypes.func,
      // position: MapPropTypes.latlng,
    }

    //Custom Marker List Component

    const MarkerList = ({ markers }) => {

      const items = markers.map(({ key, ...props }) => (
        <MyPopupMarker key={key} {...props} />
      ))
      return <div style={{display: 'none'}}>{items}</div>

    }

    MarkerList.propTypes = {
        markers: MapPropTypes.array.isRequired,
    }

    // console.log('markers', markers)


    return (
      <div>
        <Map
          center={center}
          zoom={this.state.zoom}
          style={styles.map}>

          <TileLayer
            url='https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png'
            attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          />

          <MarkerList markers={markers} />

        </Map>

        <Drawer
          width={500}
          openSecondary={true}
          docked={false}
          open={this.state.open}
          onRequestChange={(open) => this.setState({open})}
          containerStyle={styles.whitebox}
        >
    {
      markers.map((cf, k) => (
            <Card
              style={styles.appMedia}
              key={k}
              >

              <CardTitle
                titleStyle={styles.drawTitle}
                subtitleStyle={styles.drawTitle}
                title={cf.key}
                subtitle="Common Field Equipment"/>
            </Card>
          ))
    }

        </Drawer>
      </div>
    );
  }
}

export default Mapper;

How to get multiple matrices from large data sets based on year

before I start here is a a small subset of the data I'm working with, i apologize in advance for it being so large (note this is only the first 30 rows of an extremely large dataset:

mydata<-structure(list(ParkName = c("SEP", "CSSP", 
                        "SEP", "ONF", "SEP", 
                        "ONF", "SEP", 
                        "CSSP", "ONF", 
                        "SEP", "CSSP", 
                        "PPRSP", "PPRSP", 
                        "SEP", "ONF", 
                        "PPRSP", "ONF", 
                        "SEP", "SEP", 
                        "ONF"), 
           Year = c(2001, 2005, 1998,2011, 1991, 1991, 1991, 1991, 1991, 1992, 1992, 1992, 1992, 1992,
                                          1992, 1992, 1992, 1993, 1994, 1994), 
           LatinName = c("Mola mola", "Clarias batrachus", "Lithobates catesbeianus", "Rana catesbeiana", "Rana catesbeiana", 
                         "Rana yellowis", "Rana catesbeiana", "Solenopsis sp1","Rana catesbeiana", "Rana catesbeiana",
                         "Pratensis", "Rana catesbeiana",  "Rana catesbeiana", "sp2", "Orchidaceae",
                         "Rana catesbeiana","Formica", "Rana catesbeiana", "Rana catesbeiana", "sp2"), 
           NumTotal = c(1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 100, 2, 1, 2)), Names = c("ParkName", "Year", "LatinName", 
                                                                                                                      "NumTotal"),
      row.names = c(NA, -20L), class = c("tbl_df", "tbl",  "data.frame"))

This dataset represents the abundance of different species in different parks over a multitude of years. What I essentially want to do with this data is to get a species X park matrix for every year that data was recorded and then youse the 'vegan' package to calculate diversity indices for each park for each year. Obviously this is not a balanced dataset as not every park recorded species abundance for every year etc. Now I've realized to do this I need to run loops. I would need to get a list of parks per year and a list of species and their abundance per park per year in order to create these matrices. I'm not the greatest when it comes to running loops and this task is confusing me. For example, I created a separate vector of unique years in the dataset. I then created an empty list called "parkbyyear" to fill up with a list of parks by year from the main dataframe

year<-as.vector(unique(data[,3]))
parkbyyear<-NULL

for (i in 1:year) {
  parkbyyear[i]<- mydata[mydata$ParkName[year == "i"]
}

The loop fails to run. Any help would be appreciated.

4

1 回答 1

1

您的handleToggle方法是组件的onClick处理程序Marker。React 中的onClick处理程序默认传递一个合成事件对象(更多信息在这里)。

因此,index传递给该handleToggle方法的将是合成事件对象,它不会帮助您从places数组中获取标记的索引。您必须将索引显式传递到您的handleToggle方法中。为此,您需要进行以下更改:

1> 将构造函数中函数的绑定改为:

this.handleToggle = this.handleToggle.bind(this,index);

2> 在MyPopupMarker组件中显式传递索引:

const MyPopupMarker = ({ children, position,index }) => (
<Marker
        onClick={()=>this.handleToggle(index)}
 ....
 )

3> 将索引传递给MyPopupMarker组件中的MarkerList组件

 const items = markers.map(({ key, ...props },i) => (
    <MyPopupMarker key={key}  index={i} {...props}/>
  ))

4> 从对象places中的数组state而不是props对象中访问索引。

handleToggle(index) {

    const self = this;

    self.setState({
      open: !this.state.open,
      places: markers
    });

    var selectedMarker = this.state.places[index];

    console.log(this.state.places)
  }

错误消息无法读取未定义的属性 '#<Object>' 的原因是您试图访问它所在的对象中的places数组。propsundefined

顺便说一句,我想指出在render方法中创建组件(组件MyPopupMarkerMarkerList)不是一个好习惯,因为这些组件将在每次渲染时创建,这将是浪费的。Mapper如果您在组件 之外声明它们会更有效率。编辑:

要将组件移出,render您需要将handleToggle函数传入 as props。我已将您的代码更改如下:

MyPopupMarker 组件:该组件获取indexhandleToggle函数作为道具。

const MyPopupMarker = ({ children, position, index, handleToggle }) => (
  <Marker onClick={() => handleToggle(index)} position={position}>
    <Popup>
      <span>{children}</span>
    </Popup>
  </Marker>
);

MarkerList 组件:该组件将handleToggle函数作为 props 并将其MyPopupMarkerindex

const MarkerList = ({ markers, handleToggle }) => {
  const items = markers.map(({ key, ...props }, i) => (
    <MyPopupMarker key={key} {...props} index={i} handleToggle={handleToggle} />
  ));
  return <div >{items}</div>;
};

Mapper 组件:该组件将handleToggle函数MarkerListmarkers

class Mapper extends Component {
  constructor(props) {
    super(props);

    this.handleToggle = this.handleToggle.bind(this);
    this.handleClose = this.handleClose.bind(this);

    this.state = {
      lat: 29.761993,
      lng: -95.366302,
      zoom: 4,
      open: false,
      places: []
    };
  }

  handleToggle(index) {
    const self = this;

    self.setState({
      open: !this.state.open,
      places: markers
    });

    // index = this.props.places[index]

    let selectedMarker = this.state.places[index];

    console.log(selectedMarker);
  }

  handleClose() {
    this.setState({
      open: false
    });
  }

  render() {
    const center = [this.state.lat, this.state.lng];


    let selectedMarker = this.state.places;

    return (
      <div>
        <Map center={center} zoom={this.state.zoom} style={styles.map}>
          <TileLayer
            url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"
            attribution="&copy; <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"
          />

          <MarkerList markers={markers} handleToggle={this.handleToggle} />
        </Map>

        <Drawer
          width={500}
          openSecondary={true}
          docked={false}
          open={this.state.open}
          onRequestChange={open => this.setState({ open })}
          containerStyle={styles.whitebox}
        >

          {selectedMarker.map((value, index) => (
            <Card style={styles.appMedia} key={index}>
              <CardTitle
                titleStyle={styles.drawTitle}
                subtitleStyle={styles.drawTitle}
                title={value.key}
                subtitle="Common Field Equipment"
              />
            </Card>
          ))}
        </Drawer>
      </div>
    );
  }
}

export default Mapper;

完整的工作示例可以在https://codesandbox.io/s/4r1yo07kw9找到

于 2017-11-05T22:50:19.233 回答