title: Remove Zoom control from map in react-leaflet
body: <p>I am building a react-leaflet application, and I am trying to separate the zoom control from the map itself.  The same question in a vanilla Leaflet context was asked here: <a href="https://gis.stackexchange.com/questions/186131/placing-controls-outside-map-container-with-leaflet">Placing controls outside map container with Leaflet?</a>.  This is what I'm trying to accomplish within the react-leaflet framework.  Here is the general outline of my project:</p>
  
  <pre class="lang-js prettyprint-override"><code>import UIWindow from './UIWindow'
  import Map from './MapRL'
  
  class App extends React.Component {
     render () {
        return (
           &lt;div className="App"&gt;
              &lt;Map /&gt;
              &lt;UIWindow /&gt;
           &lt;/div&gt;
        )
     }
  }
  
  export default App;
  </code></pre>
  
  <p>My map component looks like this:</p>
  
  <pre class="lang-js prettyprint-override"><code>import React from 'react'
  import { Map as LeafletMap, TileLayer } from 'react-leaflet'
  
  class Map extends React.Component {
  
     render () {
        return(
           &lt;LeafletMap
              className="sidebar-map"
              center={...}
              zoom={...}
              zoomControl={false}
              id="mapId" &gt;
  
              &lt;TileLayer
                  url="..."
                  attribution="...
              /&gt;
  
           &lt;/LeafletMap&gt;
        )
     }
  }
  
  export default Map;
  </code></pre>
  
  <p>Then my UIWindow looks like this:</p>
  
  <pre class="lang-js prettyprint-override"><code>class UIWindow extends React.Component {
     render () {
        return(
           &lt;div className="UIWindow"&gt;
              &lt;Header /&gt;
              &lt;ControlLayer /&gt;
           &lt;/div&gt;
        )
     }
  }
  </code></pre>
  
  <p>And finally, my ControlLayer (where I want my ZoomControl to live) should look something like this:</p>
  
  <pre class="lang-js prettyprint-override"><code>class ControlLayer extends React.Component {
     render () {
        return (
           &lt;div className="ControlLayer"&gt;
              &lt;LeftSidebar /&gt;
              &lt;ZoomControl /&gt;
              {this.props.infoPage &amp;&amp; &lt;InfoPage /&gt;}
           &lt;/div&gt;
        )
     }
  }
  </code></pre>
  
  <p>Of course with this current code, putting ZoomControl in the ControlLayer throws an error: <em>TypeError: Cannot read property '_zoom' of undefined</em>, with some more detailed writeup of what's wrong, with all the references the Leaflet's internal code regarding the zoom functionality.
  (<code>DomUtil.removeClass(this._zoomInButton, className);</code>, etc.)</p>
  
  <p>I expected an error, because the ZoomControl is no longer a child of the <code>&lt;Map /&gt;</code> component, but rather a grandchild of the <code>&lt;Map /&gt;</code>'s sibling.  I know react-leaflet functions on its context provider and consumer, LeafletProvider and LeafletConsumer.  When I try to call on my LeafletConsumer from within my <code>&lt;ControlLayer /&gt;</code>, I get nothing back.  For example:</p>
  
  <pre class="lang-js prettyprint-override"><code>            &lt;LeafletConsumer&gt;
                 {context =&gt; console.log(context)}
              &lt;/LeafletConsumer&gt;
  </code></pre>
  
  <p>This logs an empty object.  Clearly my LeafletConsumer from my ControlLayer is not properly hooked into the LeaflerProvider from my <code>&lt;Map /&gt;</code>.  Do I need to export the context from the Map somehow using LeafletProvider?  I am a little new to React Context API, so this is not yet intuitive for me.  (Most of the rest of the app will be using React Redux to manage state changes and communication between components.  This is how I plan to hook up the contents of the sidebar to the map itself.  My sidebar doesn't seem to have any problem with being totally disconnected from the <code>&lt;Map /&gt;</code>).</p>
  
  <p>How can I properly hook this ZoomControl up to my Map component?</p>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>I tried capturing the context in my redux store, and then serving it to my externalized ZoomControl.  Like so:</p>
  
  <pre class="lang-js prettyprint-override"><code>            &lt;LeafletConsumer&gt;
                 { context =&gt; {
                    this.props.captureContext(context)
                 }}
              &lt;/LeafletConsumer&gt;
  </code></pre>
  
  <p>This captures the context as part of my redux store.  Then I use this as a value in a new context:</p>
  
  <pre class="lang-js prettyprint-override"><code>// ControlLayer.js
  
  const MapContext = React.createContext()
  
              &lt;MapContext.Provider value={this.props.mapContext}&gt;
                 &lt;LeftSidebar /&gt;
                 &lt;MapContext.Consumer&gt;
                    {context =&gt; {
                       if (context){
                          console.log(ZoomControl);
  
                       }
                    }}
                 &lt;/MapContext.Consumer&gt;
              &lt;/MapContext.Provider&gt;
  </code></pre>
  
  <p>Where <code>this.props.mapContext</code> is brought in from my redux matchStateToProps, and its exactly the context captured by the captureContext function.</p>
  
  <p>Still, this is not working.  My react dev tools show that the MapContent.Consumer is giving the exact same values as react-leaflet's inherent '' gives when the ZoomControl is within the Map component.  But I still get the same error message.  Very frustrated over here.</p>