37

I am working on a project to combine React and Leaflet, but I must say I am having some hard time with the semantics.

As most of the stuff is managed by Leaflet directly, I don't know if it would make sense to add the Leaflet map instance as state in the React Component or not.

Same problem when it comes to creating markers with Leaflet, as it does not return anything, I don't have anything to render really. The logic itself seems blurry to me.

Here is what I started to make. It's working but I feel like I'm writing bad code and missing the concept.

/** @jsx React.DOM */

/* DOING ALL THE REQUIRE */
var Utils = require('../core/utils.js');

var Livemap = React.createClass({
    uid: function() {
        var uid = 0;
        return function(){
            return uid++;
        };
    },
    getInitialState: function() {
        return {
            uid: this.uid()
        }
    },
    componentDidMount: function() {
        var map = L.map('map-' + this.state.uid, {
            minZoom: 2,
            maxZoom: 20,
            layers: [L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'})],
            attributionControl: false,
        });
        map.fitWorld();
        return this.setState({
            map: map
        });
    },
    render: function() {
        return (
            <div className='map' id={'map-'+this.state.uid}></div>
        );
    }
});

(function(){
    Utils.documentReady(function(){
        React.render(
            <Livemap />,
            document.body
        )
    });
})();

So my questions are:

  • Does this sample seem legit?
  • How would you approach the logic of adding markers and managing their events?

2 Answers 2

43
  • You don't need to manage uniqueness, i.e. "UID", yourself. Instead, you can use getDOMNode to access the component's real node. Leaflet's API supports either a string selector or an HTMLElement instance.
  • Leaflet is managing rendering, so the map should not live on state. Only store data in state that affects React's rendering of the DOM element.

Beyond those two points, use the Leaflet API normally and tie callbacks from your React component to the Leaflet map as you like. React is simply a wrapper at this point.

import React from 'react';
import ReactDOM from 'react-dom';

class Livemap extends React.Component {

    componentDidMount() {
        var map = this.map = L.map(ReactDOM.findDOMNode(this), {
            minZoom: 2,
            maxZoom: 20,
            layers: [
                L.tileLayer(
                    'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                    {attribution: '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'})
            ],
            attributionControl: false,
        });

        map.on('click', this.onMapClick);
        map.fitWorld();
    }

    componentWillUnmount() {
        this.map.off('click', this.onMapClick);
        this.map = null;
    }

    onMapClick = () => {
        // Do some wonderful map things...
    }

    render() {
        return (
            <div className='map'></div>
        );
    }

}
9
  • Hello I am wondering if you could take the time to explain me some stuff relating to the use of Leaflet and React. I want to add some very customized marker (so I will use iconDiv with some html in it) and want to add different event on those elements (the marker itself and some specific part of the marker) how would you do it ? Since ReactComponent don't really return html.
    – Swann
    Commented Nov 12, 2014 at 8:47
  • @SwannPolydor, I'm not sure what you mean by that. Can you open a new question and post some code?
    – Ross Allen
    Commented Nov 12, 2014 at 14:59
  • Correct me if I'm wrong, but this solution builds a new map on every Livemap render, doesn't it? Shouldn't we avoid this situation? Commented Dec 16, 2015 at 9:11
  • 1
    Because render returns the same thing every time, React will never touch the real DOM after the first render. This won't build a new map on every re-render. To improve this even more, you can tell React never to update as suggested in using React with other libraries by returning false from shouldComponentUpdate.
    – Ross Allen
    Commented Dec 18, 2015 at 18:36
  • 1
    @GiorgiMoniava React.createClass "autobound" functions declared on Objects passed to it. If you use createClass you do not need a separate bind call. If you are using ES6 classes, you are definitely right; you need to bind.
    – Ross Allen
    Commented Mar 8, 2017 at 1:33
23

As an additional, less-detailed answer, PaulLeCam's react-leaflet component seems popular. Haven't used it yet but it looks promising:

https://github.com/PaulLeCam/react-leaflet

UPDATE: It's solid. Haven't used many of the features yet but the codebase is well-written and easy to follow and extend, and what I've used works great out of the box.

2
  • How do you use the base components he provides? Are these supposed to be used as separate React components outside of the <Map /> component?
    – maxwell
    Commented Jul 6, 2016 at 22:03
  • @maxwell depends on your needs -- I generally render them within <Map> at some point down the component tree.
    – ericsoco
    Commented Jul 6, 2016 at 23:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.