Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to write a component which outputs Markers? #103

Closed
varya opened this issue Nov 22, 2015 · 12 comments
Closed

How to write a component which outputs Markers? #103

varya opened this issue Nov 22, 2015 · 12 comments

Comments

@varya
Copy link
Contributor

varya commented Nov 22, 2015

How a custom react component which outputs Marker on map should be written? I need to have smth like this working:

import MyMarker from './MyMarker.js';

const builtMarker = (function() {
  const position = [51.520, -0.11];
  return (
    <MyMarker position={position}/>
  );
})();

render(
  <div>
    <h1>Hello, world!</h1>
    <div className="map">
        <Map center={center} zoom={13}>
            <TileLayer
            url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
            attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
            />
            {builtMarker}
        </Map>
    </div>
  </div>
  ,
  document.getElementById('example')
);

I made MyMarker component like that https://github.com/varya/react-leaftlet-test/blob/master/src/MyMarker.js but this gets error:

Uncaught TypeError: Cannot read property 'addLayer' of undefined

I guess the component should not only extend MapLayer but also provide special interface. What is missing? I could not find similar example in the docs.

Also, what should I do to output several Markers? I mean, in React it's required to be in a single wrapper. But it cannot be just <div> for the map. How this wrapper should be written?

PS: This is the repo where I demonstrate my case https://github.com/varya/react-leaftlet-test

@surkova
Copy link

surkova commented Nov 22, 2015

I don't know if it's the right approach in React world, but I did the following and it worked:

import React, {Component} from 'react';
import {Marker, Popup} from 'react-leaflet';

class MyMarker extends Marker {

  componentWillMount() {
    super.componentWillMount();
  }

  render () {
    return (
        <Marker position={this.props.position}>
            <Popup>
                <span>A pretty CSS3 popup.<br/>Easily customizable.</span>
            </Popup>
        </Marker>
    )
  }
}

export default MyMarker;

You were simply missing map, that's passed via const { map, position, ...props } = this.props; in Marker.js

@varya
Copy link
Contributor Author

varya commented Nov 22, 2015

@surkova, this does not help. But I updated the repo with componentWillMount anyway, just to demonstrate that this does not work.

@surkova
Copy link

surkova commented Nov 22, 2015

Then yet another suggestion:

import React, {Component} from 'react';
import {marker} from 'leaflet';
import {MapLayer} from 'react-leaflet';

class MyMarker extends MapLayer {
  componentWillMount() {
    super.componentWillMount();
    const { map, position, popupText, ...props } = this.props;
    this.leafletElement = marker(position, props).bindPopup(popupText);
  }
  render() {
    return this.renderChildrenWithProps({
      layerGroup: this.leafletElement,
    });
  }
}

export default MyMarker;
const builtMarker = (function() {
  const position = [51.520, -0.11];
  const popupText = "A pretty CSS3 popup.<br/>Easily customizable."
  return (
    <MyMarker position={position} popupText={popupText}/>
  );
})();

@varya
Copy link
Contributor Author

varya commented Nov 22, 2015

Thank you very much, but the point is to use Marker react component. Of course it's possible to create markers on the low level, but then the usage of react-leaflet doesn't make any sense.

@PaulLeCam
Copy link
Owner

As written in the documentation, you need to pass the map property injected by the <Map> component to children components.

Ex:

const MyMarker = ({ map, position }) => (
  <Marker map={map} position={position}>
    <Popup>
      <span>A pretty CSS3 popup.<br/>Easily customizable.</span>
    </Popup>
  </Marker>
);

...

<Map center={center} zoom={13}>
  <TileLayer
    url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
    attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
  />
  <MyMarker position={position} />
</Map>

@varya
Copy link
Contributor Author

varya commented Nov 23, 2015

@PaulLeCam, thank you for the answer. This example works. But I'm also wondering how to insert a variable or a set of Markers. This would be nice to have an example in examples with a custom component which outputs a list of markers. I think many will be clear from such an example.

@PaulLeCam
Copy link
Owner

What do you mean by variable and set of markers?
At this point it is just React, so you can apply usual patterns that work with it.

Ex:

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

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

...

class MyMap extends Component {
  ...
  render() {
    // Probably generated dynamically, but the logic is the same                            
    const markers = [
      {key: 'marker1', position: [51.5, -0.1], children: 'My first popup'},
      {key: 'marker2', position: [51.51, -0.1], children: 'My second popup'},                  
    ];

    return (
      <Map ...>
        <TileLayer .../>
        <MyMarkersList markers={markers} />
      </Map>
    );
  }
}

The only constraint if you want to render a list in a component is to wrap it in a container, this is purely a React constraint.
In our case having Leaflet actually render the layers, a possible solution is to wrap them in a div with display: none.

paazmaya added a commit to paazmaya/kanigawa that referenced this issue Nov 23, 2015
@varya
Copy link
Contributor Author

varya commented Nov 23, 2015

Thank you very much! Now it's clear.
I made a pull request with this code into your set of examples. This is the place where I was looking for an answer before asked here. Maybe someone else will also look there :-)
#104

@varya varya closed this as completed Nov 23, 2015
@PaulLeCam
Copy link
Owner

Glad it helps!
Thanks for your PR, I'll merge it.

@taozhi8833998
Copy link

map and layerContainer is not passed to child componet in react-leaflet 1.1.1 version ???

@felixsonyusuftosin
Copy link

I have set up map like this

render(){
     return(
    <Map  className="markercluster-map"  ref = "map" maxZoom = {30} minZoom ={2} center={this.props.markers[0].position}  zoom={9}>
          <BingTileLayer url = '' bingKey='<bingmapskey>'  type='aerial' />
           {
            this.props.markers?
              <MarkerClusterGroup   wrapperOptions={{enableDefaultStyle: true}}  >
                 <GeoJSON    ref='geojd' data = {this.geoj}  onEachFeature = {this.onEachDot }/>
            </MarkerClusterGroup>
            :
            null
        }



      </Map>
     ) }

What i require is to have access to my GeoJSON Layer via

componentDidMount(){
let th = this;
this.map = this.refs.map.leafletElement;

   this.geojson = this.refs.geojd.leafletElement 
        console.log(this.geojson);           
    
     }

@topgun743
Copy link

topgun743 commented Nov 6, 2017

I have a question in this regard.
I have 20 different sets of markers, with each set comprising of minimum 50 markers (in production may be much more than that).
In my current application when I iterate over these sets of markers for rendering, it freezes my UI causing frustration to the end user.

How can I render these sets on leaflet map asynchronously. What is the best approach?
And also, can the leaflet map L.map instance be approached by multiple simultaneously executing blocks of code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants