Reputation: 15003
I am trying to express my Openlayers application as a components based application. Having a single <Map />
component with childrens like <Marker />
, I need to access my <Map />
component's this.map
property from the <Marker />
.
Take this markup from a representational component:
<Map center={[-1.81185, 52.44314]} zoom={6}>
<Marker title="This is a marker" coordinate={[-1.81185, 52.44314]} />
</Map>
The <Map />
component:
export default class Map extends React.Component {
static propTypes = {
center: React.PropTypes.array.isRequired,
zoom: React.PropTypes.number.isRequired
}
constructor(props) {
super(props);
this.map = null;
}
componentDidMount() {
this.map = new ol.Map(/* code removed for brevity */);
}
renderChildren() {
const { children } = this.props;
if (!children) return;
return React.Children.map(children, c => {
return React.cloneElement(c, {
map: this.map
});
})
}
render() {
return <div id="map">{this.renderChildren()}</div>
}
}
The <Marker />
component:
export default class Marker extends React.Component {
static propTypes = {
map: React.PropTypes.object,
coordinate: React.PropTypes.array.isRequired,
title: React.PropTypes.string
}
componentDidMount() {
const { map, coordinate, title } = this.props;
if (!map) return;
var marker = createMarkerAndPlaceOn(map);
}
render() {
return null;
}
}
As you can see I tried passing the this.map
property down, by cloning the element and give it the property.
However, because I need to rely on the DOM node #map
to be rendered, I can first initialize my new ol.Map()
in the <Map />
's componentDidMount()
method. This means my child component does not get the instance of this.map
when rendering.
Is there any clean, non anti-pattern, way of achieving this?
Upvotes: 1
Views: 66
Reputation: 28397
You can store map
in the state
and it'll be passed down to the children as soon as it's ready.
constructor(props) {
super(props);
this.state = {
map: null
}
this.renderChildren = this.renderChildren.bind(this);
}
componentDidMount() {
this.setState({map : new ol.Map()});
}
renderChildren() {
const { children } = this.props;
if (!children)
return;
if(!this.state.map)
return <div>Loading markers</div>
return React.Children.map(children, c => {
return React.cloneElement(c, {
map: this.state.map
});
})
}
Upvotes: 2