When I'm creating leaflet marker like this:
<Marker position={[marker.lat, marker.lng]}>
<Popup>
<span>A pretty CSS3 popup. <br/> Easily customizable.</span>
</Popup>
</Marker>
Is there way to access not react component that was returned by <Marker />, but leafletElement that was created by marker function from leaflet.js library?
So, when I'll be using Marker as a child in my custom component like:
<MyCustomComponent>
<Marker position={[marker.lat, marker.lng]} />
<Marker position={[marker.lat, marker.lng]} />
</MyCustomComponent>
// ...
class MyCustomComponent extends LayerGroup {
// ...
this.props.children.forEach((reactLeafletMarker) => {
// object that was created by **maker** func. imported **from leaflet**
reactLeafletMarker.leafletElement;
});
// ...
}
Currently, when I'm accessing to the child react-leaflet marker component inside MyCustomComponent:
<MyCustomComponent>
<Marker position={[marker.lat, marker.lng]} />
<Marker position={[marker.lat, marker.lng]} />
</MyCustomComponent>
// ...
this.props.children.forEach((reactLeafletMarker) => {
// react-leaflet marker component
reactLeafletMarker;
});
// ...
I have available only the next object keys:
$$typeof: Symbol(react.element)
key: null
props: Object
ref: null
type: function Marker()
_owner: ReactCompositeComponentWrapper
_store: Object
_self: null
_source: null
__proto__: Object
Additionally to that key, I would like to have something like leafletElement.
https://github.com/PaulLeCam/react-leaflet/blob/master/src/Marker.js#L30
Is it possible to assign marker to component, like:
createLeafletElement (props: Object): Object {
const { position, ...options } = props
const leafletMarker = marker(position, this.getOptions(options));
this.leafletElement = leafletMarker;
return leafletMarker;
}
So the leafletElement will be available on marker component.
Hi,
The leafletElement is already defined in the Marker instance (cf the MapLayer implementation), so you can access it using the ref like any other element, ex:
class MyComponent extends React.Component {
bindMarker = (ref) => {
if (ref) {
console.log('marker element', ref.leafletElement)
}
}
render () {
return <Marker ref={this.bindMarker} {...this.props} />
}
}
I need to access marker, not inside React Component that renders some map, but inside react-leaflet LayerGroup.
Markers are sending to that LayerGroup as children's.
class MyComponent extends React.Component {
// That is you'r example:
bindMarker = (ref) => {
if (ref) {
console.log('marker element', ref.leafletElement)
}
}
render () {
return (
<MyCustomPlugin>
<Marker ref={this.bindMarker} {...this.props} />
<Marker ref={this.bindMarker} {...this.props} />
</MyCustomPlugin>
)
}
}
class MyCustomPlugin extends LayerGroup {
componentDidMount() {
this.props.children.forEach((reactLeafletMarker) => {
// that is where I need to have leafletElement
reactLeafletMarker.leafletElement;
});
}
}
The current solution, that was proposed:
class MyCustomPlugin extends LayerGroup {
componentDidMount() {
const listOfLeafletElements = [];
this.props.children.forEach((reactLeafletMarker) => {
React.cloneElement(reactLeafletMarker, { ref: (marker) => {
listOfLeafletElements.push(marker.leafletElement);
});
});
}
Full example:
https://github.com/YUzhva/react-leaflet-markercluster/pull/16/files#diff-08e906cca00ce6702663aa1e3c2c5263R157
But that is kind of heavy solution, because each time when we receiving a list of markers, we need to iterate twice:
That would be faster if Marker will have leafletElement from start, so there will be only one iteration that just adding that marker to map.
Sorry I don't get what you mean by "Marker will have leafletElement from start"? The Leaflet element is created by the Marker component itself when it's about to mount, that how everything else works in this library.
If your problem is getting multiple markers, no need to clone the element, you can simply adapt the bindMarker() handler, ex:
class MyComponent extends React.Component {
markers = []
bindMarker = (ref) => {
if (ref) {
this.markers.push(ref.leafletElement)
}
}
componentDidMount () {
console.log('markers', this.markers)
}
render () {
return (
<MyCustomPlugin>
<Marker ref={this.bindMarker} {...this.props} />
<Marker ref={this.bindMarker} {...this.props} />
</MyCustomPlugin>
)
}
}
If you need to access the markers before componentDidMount(), I don't think this will be possible directly, in that case you should create a custom component using Leaflet directly to implement the logic you want.
@PaulLeCam Notice, that MyComponent where you are getting ref.leafletElement and < MyCustomPlugin> - are different components.
leafletElement should be accessible inside MyCustomPlugin
(not inside MyComponent where are you writing that bindMarker function, please read above example).
<Marker {...this.props} /> sending to the <MyCustomPlugin/> as children:
class MyCustomPlugin {
this.props.children // that is <Marker {...this.props} />
}
And that children should have a way to get marker leafletElement.
Yes that's the way React works, as far as I know. Seems to me the problem you're having is about accessing React instances, not the actual Leaflet element.
Okay. I'll try to record a video...
Thank you, for fast responses (=
Video (UPD: link is dead) - it's better to watch on speed 1.25x (=
Hi,
I don't think it is possible to do what you want, there seem to be some confusion between the React elements and instances, because when you iterate over this.props.children from your containing component instance, you're iterating over the React elements, not the created instances. That's what refs are for, they allow to get access to the instance.
I don't know of another way than cloning the elements before rendering to dynamically inject extra props, that's the way it's done in the LayersControl component for example, as long as you want to use the provided Marker.
An alternative could be to create a custom Marker component that would use a context function injected by the MarkerCluster to notify it when it gets (un)mounted, this way it wouldn't need to clone the children.
Sorry if it's not the answer you expect, I understand the problem as I've been through it notably to implement the LayersControl so if there is a better way to do this I'd like to know, but it's the only one I found.
Yep...
Looks like there is not way, to make static function that will be accessible from parent component without rendering Marker )=
Thanks, for support.