yuzhva / react-leaflet-markercluster

React wrapper of the official Leaflet.markercluster for react-leaflet
https://yuzhva.github.io/react-leaflet-markercluster/
MIT License
284 stars 101 forks source link

Importing MarkerClusterGroup results in TypeError #71

Open reggie3 opened 6 years ago

reggie3 commented 6 years ago

I am receiving the following error when trying to use this package.

TypeError: Super expression must either be null or a function, not object

The entire error is shown here: image

The error is associated with these lines of code in the react-leaflet-markcluster.js file (line numbers differ from what is shown in the error because of Chrome debugger formatting) image

I am trying to use the package in a Gatsby project, but I don't think that is causing the error. I am successfully able to import and use the react-leaflet project.

Version Info:

"react-leaflet": "^2.0.0",
"react-leaflet-markercluster": "^1.1.8",
"leaflet": "^1.3.1",
"leaflet.markercluster": "^1.3.0",
"gatsby": "^1.9.273",

Related Import Statements

import {
  Map,
  TileLayer,
  Marker,
  Popup,
} from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import MarkerClusterGroup from 'react-leaflet-markercluster/dist/react-leaflet-markercluster';
import 'react-leaflet-markercluster/dist/styles.min.css'; 
oserban commented 6 years ago

I have the same issue with:

"leaflet": "^1.3.1",
"leaflet.markercluster": "^1.3.0",
"react-leaflet": "^2.0.0-rc.3",
"react-leaflet-markercluster": "^1.1.8",

Is there a recommended version for these libraries?

yuzhva commented 6 years ago

This plugin does not support react-leaflet v2.

ThiefMaster commented 6 years ago

Any plans to update it to include v2 support?

yuzhva commented 6 years ago

@ThiefMaster yep, I will try to deliver it during the next week. The trick is that react-leaflet was as the candidate release till that day.

So since today, I need to update this lib. I will update package.json dependency to solve that issue in v1.1.9.

And since v2.0 there will be support of react-leaflet ^2.0 latest React context from 16.3

webcarrot commented 6 years ago

Temporary version:

import { MapLayer, withLeaflet } from "react-leaflet";
import L from "leaflet";

require("leaflet.markercluster");

class MarkerClusterGroup extends MapLayer {

  createLeafletElement(props) {
    const el = new L.markerClusterGroup(props);
    this.contextValue = {
      ...props.leaflet,
      layerContainer: el
    };
    return el;
  }

}

export default withLeaflet(MarkerClusterGroup);
yuzhva commented 6 years ago

@webcarrot Many thanks for your contribution!

@reggie3 @oserban @ThiefMaster

Currently, the latest version with support of react-leaflet v2.0 and React 16.3 context API available as candidate release:

yarn add react-leaflet-markercluster@next # yarn
npm install react-leaflet-markercluster@next # npm

After the README and demo-app will be updated will publish it as release package.

P.S: it's stable and I think there would no be any changes in final release, so enjoy it (=

webcarrot commented 6 years ago

Hi.

  1. In react-leaflet-markercluster@next version markers pop-ups do not display content - probably they need map from props.leaflet to be set/provided in MarkerClusterGroup instance contextValue.
  2. In my temporary version events handlers are "automagically" used by L.markerClusterGroup plugin so probably there is no need to reduce/filter/split props in createLeafletElement to handle events manually.
  3. This temporary version simply drop support for deprecated API (markers, options etc.).

Sorry for my English.

yuzhva commented 6 years ago

@webcarrot

In react-leaflet-markercluster@next version markers pop-ups do not display content - probably they need map from props.leaflet to be set/provided in MarkerClusterGroup instance contextValue.

Yep, you are right. Already fixed it in 2.0.0-rc2 so it's published.

events handlers are "automagically" Just it's semantically inconveniently to use it. When you are writing some event handler on a cluster like:

<MarkerClusterGroup onClusterClick={} onCLusterMouseOver={} />

The repeating word Cluster seems superfluous

<MarkerClusterGroup onClick={} onMouseOver={} />

Gives a cleaner way of using props for event handlers.

oserban commented 6 years ago

The 2.0.0-rc3 version works flawlessly with my use case. Thanks.

webdobe commented 6 years ago

I'm getting similar behavior and cannot get past it for the life of me.

"leaflet": "^1.3.2",
"leaflet.markercluster": "^1.3.0",
"react-leaflet": "^2.0.0",
"react-leaflet-markercluster": "^2.0.0-rc3",

I hit the error:

leaflet.markercluster-src.js?d09f:17 Uncaught ReferenceError: L is not defined
    at eval (leaflet.markercluster-src.js?d09f:17)
    at L.MarkerClusterGroup.L.FeatureGroup.extend.options.maxClusterRadius (leaflet.markercluster-src.js?d09f:8)
    at eval (leaflet.markercluster-src.js?d09f:11)
    at Object.<anonymous> (bundle.js:11987)
    at __webpack_require__ (bundle.js:20)
    at eval (react-leaflet-markercluster.min.js?a99b:1)
    at Object.<anonymous> (bundle.js:11976)
    at __webpack_require__ (bundle.js:20)
    at eval (MarkersLayer.js?ba8d:4)
    at Object.<anonymous> (bundle.js:11964)
(anonymous) @ leaflet.markercluster-src.js?d09f:17
L.MarkerClusterGroup.L.FeatureGroup.extend.options.maxClusterRadius @ leaflet.markercluster-src.js?d09f:8

If I add leaflet.js directly to the index.html Then I get the same error that started this thread.

react-leaflet-markercluster.min.js?a99b:1 Uncaught TypeError: Cannot read property 'markerClusterGroup' of undefined
    at t.value (react-leaflet-markercluster.min.js?a99b:1)
    at t.MapLayer (MapLayer.js?a679:24)
    at new t (react-leaflet-markercluster.min.js?a99b:1)
    at constructClassInstance (react-dom.development.js?cada:11447)
    at updateClassComponent (react-dom.development.js?cada:13144)
    at beginWork (react-dom.development.js?cada:13824)
    at performUnitOfWork (react-dom.development.js?cada:15863)
    at workLoop (react-dom.development.js?cada:15902)
    at HTMLUnknownElement.callCallback (react-dom.development.js?cada:100)
    at Object.invokeGuardedCallbackDev (react-dom.development.js?cada:138)

I'v tried @webcarrot's recommendation and still no dice. I have tried playing with 1000 different dependency combinations with no success clearing npm cache etc.

Kind at a loss right now. Any help is much appreciated.

yuzhva commented 6 years ago

@webdobe

You need to install all peerDependencies:

yarn add leaflet.markercluster leaflet react-leaflet prop-types

Then install next release of that plugin:

yarn add react-leaflet-markercluster@next

Previously try to remove node_modules and clean all lock files if you have them to reset prev. versions.

webdobe commented 6 years ago

@YUzhva

Thank you soo much! I think I was missing prop-types when I was doing that exact same thing. I also ended up removing react and react-dom from my package.json and added that to the above just for good measure as it was complaining about my version of those as well.

jwmann commented 5 years ago

@YUzhva

I'm still getting the above error and I'm using 2.0.0-rc3

package.json

{
    "leaflet": "^1.4.0",
    "leaflet.markercluster": "^1.4.1",
    "react-leaflet": "^2.2.0",
    "react-leaflet-markercluster": "^2.0.0-rc3",
}

component

import { Map, CircleMarker, Tooltip, TileLayer } from 'react-leaflet';
import MarkerClusterGroup from 'react-leaflet-markercluster';

component.less

@import '~leaflet/dist/leaflet.css?url=false';
@import '~leaflet.markercluster/dist/MarkerCluster.css';
@import '~leaflet.markercluster/dist/MarkerCluster.Default.css';
@import '~react-leaflet-markercluster/dist/styles.min.css';
jwmann commented 5 years ago

Oddly, if I specifically use the dist version like the OP's example

import MarkerClusterGroup from 'react-leaflet-markercluster/dist/react-leaflet-markercluster';

It seems to work. (I had to set a maxZoom for the Map but that was a minor issue)

adambisek commented 5 years ago

For me, with react-leaflet 2 worked solution from #issuecomment-403071677 (WITHOUT USING THIS PACKAGE react-leaflet-markercluster)

import { MapLayer, withLeaflet } from '../src'
import L from "leaflet";

require("leaflet.markercluster");

class MarkerClusterGroup extends MapLayer {

  createLeafletElement(props) {
    const el = new L.markerClusterGroup(props);
    this.contextValue = {
      ...props.leaflet,
      layerContainer: el
    };
    return el;
  }

}

export default withLeaflet(MarkerClusterGroup);

Dependencies version:

    "react-leaflet": "2.2.1",
    "leaflet": "^1.4.0",
    "leaflet.markercluster": "^1.4.1",
Bigood commented 5 years ago

In case someone using Next.js stumbles upon here and use react-leaflet-universal (as I did), I confirm the rc3 works properly! You have to use next's dynamic() to import it client-side though.

import { Marker } from 'react-leaflet-universal'
//https://github.com/zeit/next.js/wiki/FAQ
//https://stackoverflow.com/questions/52939439/dynamic-import-node-module-with-next-js
import dynamic from 'next/dynamic'
const MarkerClusterGroup = dynamic(import('react-leaflet-markercluster'), {ssr: false})

...

<Map 
  //Custom component wrapping react-leaflet's Map, also loaded with dynamic()
  //Don't forget to add the maxZoom, or it'll die
  maxZoom={10} 
  >
    <MarkerClusterGroup>
        <Marker … />
        <Marker … />
        <Marker … />
    </MarkerClusterGroup>
</Map>

Deps :

    "leaflet": "^1.5.1",
    "leaflet.markercluster": "^1.4.1",
    "react-leaflet": "^2.3.0",
    "react-leaflet-markercluster": "^2.0.0-rc3",
    "react-leaflet-universal": "^2.1.0",
stereobooster commented 5 years ago
"leaflet": "1.5.1",
"leaflet.markercluster": "1.4.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-leaflet": "2.3.0",
"react-leaflet-markercluster": "2.0.0-rc3",

I get the following error

The error: _leaflet2.default.markerClusterGroup is not a constructor
stereobooster commented 5 years ago
import { MapLayer, withLeaflet } from "react-leaflet";
import "leaflet.markercluster";
import { MarkerClusterGroupProps } from "react-leaflet-markercluster";

// https://github.com/YUzhva/react-leaflet-markercluster/issues/71#issuecomment-466393028
class MarkerClusterGroup extends MapLayer {
  createLeafletElement(props: MarkerClusterGroupProps) {
    // @ts-ignore
    const el = new L.markerClusterGroup(props);
    this.contextValue = {
      ...props.leaflet,
      layerContainer: el,
    };
    return el;
  }
}

export default withLeaflet(MarkerClusterGroup);

gives this error

leaflet-src.js:1282 Uncaught TypeError: Cannot read property 'lat' of undefined
    at LatLngBounds.intersects (leaflet-src.js:1282)
    at e._recursively (leaflet.markercluster-src.js:1780)
    at e._recursivelyRemoveChildrenFromMap (leaflet.markercluster-src.js:1726)
    at e._moveEnd (leaflet.markercluster-src.js:931)
    at NewClass.fire (leaflet-src.js:593)
    at NewClass.panBy (leaflet-src.js:3313)
    at NewClass._tryAnimatedPan (leaflet-src.js:4592)
    at NewClass.setView (leaflet-src.js:3191)
    at Map.updateLeafletElement (Map.js:129)
    at Map.componentDidUpdate (Map.js:245)

UPD it seems I found why, because somehow leaflet resolves to different packages (hello webpack). As the result execution gets to this point:

function toLatLngBounds(a, b) {
    if (a instanceof LatLngBounds) {
        return a;
    }
    return new LatLngBounds(a, b);
}

where a is LatLngBounds (it has all the same methods), but it is not instance of LatLngBounds (it identifies itself as B).

Screenshot 2019-10-14 at 11 44 24
saadsaifse commented 4 years ago

@stereobooster I am stumbling upon the same problem, did you find any solution for this with Typescript?

stereobooster commented 4 years ago

@saadsaifse end up using mapbox (with open source tiles)

saadsaifse commented 4 years ago

@stereobooster that's for the base layers I presume? How did you manage to get marker clustering without Leaflet?

stereobooster commented 4 years ago

@saadsaifse first result from googling "mapbox cluster" https://docs.mapbox.com/mapbox-gl-js/example/cluster/

emilhe commented 4 years ago

I was also getting type errors, e.g. "TypeError: Cannot read property 'removeLayer' of undefined". However, using the code posted by @adambisek plus a css import, it seems to work. Here is the (slightly) modified code,

import { MapLayer, withLeaflet } from 'react-leaflet';
import L from "leaflet";

require("leaflet.markercluster");
require('react-leaflet-markercluster/dist/styles.min.css');

class MarkerClusterGroup extends MapLayer {

  createLeafletElement(props) {
    const el = new L.markerClusterGroup(props);
    this.contextValue = {
      ...props.leaflet,
      layerContainer: el
    };
    return el;
  }

}

export default withLeaflet(MarkerClusterGroup);
umitduran commented 4 years ago

@yuzhva i have same problems with below versions. I read all comments and tried a lot of things but i couldn't solve this problem. What should i try ?

Screen Shot 2020-08-31 at 09 59 40

Screen Shot 2020-08-31 at 10 00 16
yuzhva commented 4 years ago

You are not supported to use v1.4.1 of this library with react-leaflet v2 and react ^16.

Try to remove and then add leaflet.markercluster again:

yarn remove leaflet.markercluster
yarn add leaflet.markercluster

leaflet.markercluster should be of v2.0.0

umitduran commented 4 years ago

You are not supported to use v1.4.1 of this library with react-leaflet v2 and react ^16.

Try to remove and then add leaflet.markercluster again:

yarn remove leaflet.markercluster
yarn add leaflet.markercluster

leaflet.markercluster should be of v2.0.0

@yuzhva are you sure leaflet.markercluster is possible with v2.0.0 because leaflet.markercluster latest version is 1.4.1 ?

yuzhva commented 4 years ago

oh yeah, I mixed up leaflet.markercluster with this react-leaflet-markercluster package.

@umitduran what version of react-leaflet-markercluster are you using?

umitduran commented 4 years ago

@yuzhva my versions are below

yuzhva commented 4 years ago

There is a new version of react-leaflet-markercluster available - v2.0.0

Did you try to remove -rc3 and use the latest one?

yarn remove react-leaflet-markercluster
yarn add react-leaflet-markercluster
NicoTechInc commented 4 years ago

Hi all! I get the same issue. I'm using leaftlet to make some panels in grafana. First time I load my map, everything is fine, but if I go into another page with a map and then come back to my clustered map it's not reconizing my instanceof LatLngBounds in this code:

function toLatLngBounds(a, b) { if (a instanceof LatLngBounds) { return a; } return new LatLngBounds(a, b); }

Riuborth commented 3 years ago

Hi !

i've the same problem but i'm using react-leaflet 3.0.0. How long take release new version of react-leaflet-markercluster? There is another pluging like this?

yuzhva commented 3 years ago

Hello, @Riuborth

Currently, this wrapper does not work with react-leaflet v3 - the issue is already created

I will take a look at how it could be implemented with v3 during those weekends.

any contribution is welcome

UPD: The latest version with support of react-leaflet v3.0 available as a candidate release:

yarn add react-leaflet-markercluster@next # yarn
npm install react-leaflet-markercluster@next # npm
asgaraliyev commented 3 years ago

Temporary version:

import { MapLayer, withLeaflet } from "react-leaflet";
import L from "leaflet";

require("leaflet.markercluster");

class MarkerClusterGroup extends MapLayer {

  createLeafletElement(props) {
    const el = new L.markerClusterGroup(props);
    this.contextValue = {
      ...props.leaflet,
      layerContainer: el
    };
    return el;
  }

}

export default withLeaflet(MarkerClusterGroup);

import { withLeaflet,Marker} from "react-leaflet"; Attempted import error: 'withLeaflet' is not exported from 'react-leaflet'.

yuzhva commented 3 years ago

Attempted import error: 'withLeaflet' is not exported from 'react-leaflet'.

@asgaraliyev In case, if you are using v3 of react-leaflet - that example is outdated, as it has been written for v2.

sumeyradavran commented 3 years ago

I am having similar problem with v3.

'MarkerClusterGroup' cannot be used as a JSX component. Its instance type 'MarkerClusterGroup' is not a valid JSX element. Type 'MarkerClusterGroup' is missing the following properties from type 'ElementClass': render, context, setState, forceUpdate, and 3 more.ts(2786)

Here is a versions I use.

drkpkg commented 3 years ago

I am having similar problem with v3.

'MarkerClusterGroup' cannot be used as a JSX component. Its instance type 'MarkerClusterGroup' is not a valid JSX element. Type 'MarkerClusterGroup' is missing the following properties from type 'ElementClass': render, context, setState, forceUpdate, and 3 more.ts(2786)

Here is a versions I use.

Same problem, cannot visualize the map.

AliBayatpour commented 3 years ago

I have the same problem: 'MarkerClusterGroup' cannot be used as a JSX component. Its instance type 'MarkerClusterGroup' is not a valid JSX element. Type 'MarkerClusterGroup' is missing the following properties from type 'ElementClass': render, context, setState, forceUpdate, and 3 more.ts(2786) here are packages versions: "leaflet": "^1.7.1", "react-leaflet": "^3.0.2", "react-leaflet-markercluster": "^3.0.0-rc1", "leaflet.markercluster": "^1.4.1",

I'll be very thankful if anyone helps :)

moshkainer commented 3 years ago

@AliBayatpour - adding:

declare module 'react-leaflet-markercluster' { import { Component } from 'react';

// eslint-disable-next-line react/prefer-stateless-function
export default class MarkerClusterGroup extends Component { }

}

to a global.d.ts file, fixed the "'MarkerClusterGroup' cannot be used as a JSX component" for me.