jgimbel / react-leaflet-div-icon

marker that will use children as the content if the marker.
ISC License
28 stars 24 forks source link

JSX contents of DivIcon are being repainted for no reason #19

Open cherouvim opened 6 years ago

cherouvim commented 6 years ago

Whenever the host <Map> is being re-rendered, the JSX contents of the DivIcon are being re-rendered on the actual DOM from scratch. This is unnecessary and most probably bad (slow).

To reproduce you can run:

import React from "react";
import ReactDOM from "react-dom";
import { Map, TileLayer, Marker } from "react-leaflet";
import L from "leaflet";
import "../node_modules/leaflet/dist/leaflet.css";
import DivIcon from "react-leaflet-div-icon";

const imageIcon = new L.Icon({
  iconUrl: "https://placekitten.com/60/35",
  iconSize: new L.Point(60, 35)
});

const divIcon = new L.DivIcon({
  html: "<p>L.DivIcon</p>",
  iconSize: new L.Point(60, 35)
});

class X extends React.Component {
  onClick = () => {
    console.log("click");
    this.setState({ foo: "bar" });
  };

  render() {
    console.log("render");
    return (
      <div>
        <Map zoom={7} center={[6, 6]} style={{ width: "500px", height: "300px", border: "2px solid red" }}>
          <TileLayer url="https://{s}.tile.osm.org/{z}/{x}/{y}.png" />
          <Marker position={[6, 5]} icon={imageIcon} onClick={this.onClick} />
          <Marker position={[6, 6]} icon={divIcon} onClick={this.onClick} />
          <DivIcon position={[6, 7]} iconSize={new L.Point(60, 35)} onClick={this.onClick}><span>div-icon</span></DivIcon>
        </Map>
      </div>
    );
  }
}

ReactDOM.render(<X />, document.getElementById("root"));

There are 3 icons shown on the map. An L.Icon, an L.DivIcon and a DivIcon from this library. Clicking on any of the 3 icons, causes a setState which re-renders the <Map>. By inspecting with chrome you'll see that in all cases, the contents of the DivIcon are being re-calculated and repainted.