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?
Barett
  • 5,826
  • 6
  • 51
  • 55
Swann
  • 2,413
  • 2
  • 20
  • 28

2 Answers2

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>
        );
    }

}
Ross Allen
  • 43,772
  • 14
  • 97
  • 95
  • 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 Nov 12 '14 at 08:47
  • @SwannPolydor, I'm not sure what you mean by that. Can you open a new question and post some code? – Ross Allen Nov 12 '14 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? – Augustin Riedinger Dec 16 '15 at 09: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](https://facebook.github.io/react/tips/use-react-with-other-libraries.html) by returning `false` from `shouldComponentUpdate`. – Ross Allen Dec 18 '15 at 18:36
  • Note the this.getDOMNode() has been deprecated in React. You now use React.findDOMNode(this) – Phoeniceus Agelaius Jul 18 '16 at 18:29
  • Thanks, @PhoeniceusAgelaius. I updated the code to use the latest API. – Ross Allen Jul 18 '16 at 20:52
  • @RossAllen Don't you need to use bind when registering handler for the map click? e.g. this.onMapClick.bind(this)? – Giorgi Moniava Mar 07 '17 at 18:21
  • 1
    @GiorgiMoniava `React.createClass` ["autobound"](https://facebook.github.io/react/blog/2013/07/02/react-v0-4-autobind-by-default.html) 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 Mar 08 '17 at 01:33
  • @RossAllen Thanks this is good to know. Will check into it further. – Giorgi Moniava Mar 08 '17 at 05:09
21

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.

ericsoco
  • 24,913
  • 29
  • 97
  • 127
  • How do you use the base components he provides? Are these supposed to be used as separate React components outside of the component? – maxwell Jul 06 '16 at 22:03
  • @maxwell depends on your needs -- I generally render them within `` at some point down the component tree. – ericsoco Jul 06 '16 at 23:19