This is a more generalized version of my other question: Remove Zoom control from map in react-leaflet. React-leaflet comes with a handful of components which control the map - i.e. the <ZoomControl />
, <LayersControl />
, etc. But in order for these components to properly communicate with a map instance, they must be written as a child of the <Map />
component, like so:
<Map center={...} zoom={...}>
<ZoomControl />
<LayersControl />
<MyCustomComponent />
</Map>
What I am trying to create is a situation where map components that are not direct children of the map can properly communicate with the map. For example:
<App>
<Map />
<Sibling>
<Niece>
<ZoomControl />
<OtherControls />
</Niece>
</Sibling>
</App>
Obviously the trouble here is that when these controls are no longer children or descendants of the <Map />
, they don't receive the map instance through a provider. As you can see in my other question, I tried creating a new Context object and using it to provide the map to the displaced controls. That didn't work, and I'm not sure why. So far, my solution has been to use vanilla javascript to rehome these controls in the componentDidMount
of their intended parent, like so:
// Niece.js
componentDidMount(){
const newZoomHome = document.querySelector('#Niece')
const leafletZoomControl= document.querySelector('.leaflet-control-zoom')
newZoomHome.appendChild(leafletZoomControl)
}
I really hate this because now my general component structure does not reflect the application structure. My Zoom needs to be written as part of my map, but ends up in my Neice component.
Kboul's solution in my other question was simply to rebuild the zoom component from scratch and feed it the map context. This works fine for a simple zoom component, but for more complex components, I can't be rebuilding entire frameworks. For example, I made a quick react-leaflet component version of esri-leaflet's geosearch:
import { withLeaflet, MapControl } from "react-leaflet";
import * as ELG from "esri-leaflet-geocoder";
class GeoSearch extends MapControl {
createLeafletElement(props) {
const searchOptions = {
...props,
providers: props.providers ? props.providers.map( provider => ELG[provider]()) : null
};
const GeoSearch = new ELG.Geosearch(searchOptions);
// Author can specify a callback function for the results event
if (props.onResult){
GeoSearch.addEventListener('results', props.onResult)
}
return GeoSearch;
}
componentDidMount() {
const { map } = this.props.leaflet;
this.leafletElement.addTo(map);
}
}
export default withLeaflet(GeoSearch);
Its relatively simple and works great when declared inside the <Map />
component. But I want to move it to a separate place in the app, and I don't want to have to recode the entire esri Geosearch. How can I use functioning react-leaflet control components outside of the <Map />
component while properly linking it to the map instance?
Here's a quick codsandbox template to start messing with if you're so inclined. Thanks for reading.