score:4

Accepted answer

here is the same approach without hooks:

the provider should look like this:

class provider extends component {
  state = { map: null };

  setmap = map => {
    this.setstate({ map });
  };

  render() {
    return (
      <context.provider value={{ map: this.state.map, setmap: this.setmap }}>
        {this.props.children}
      </context.provider>
    );
  }
}

leaflet component will be:

class leaflet extends component {
  mapref = createref(null);

  componentdidmount() {
    const map = this.mapref.current.leafletelement;
    this.props.setmap(map);
  }

  render() {
    return (
      <map
        style={{ width: "80vw", height: "60vh" }}
        ref={this.mapref}
        center={[50.63, 13.047]}
        zoom={13}
        zoomcontrol={false}
        minzoom={3}
        maxzoom={18}
      >
        <tilelayer
          attribution='&amp;copy <a href="http://osm.org/copyright">openstreetmap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?"
        />
      </map>
    );
  }
}

and now to access the setmap function to the compoenntdidmount you need to do the following:

export default props => (
  <context.consumer>
    {({ setmap }) => <leaflet {...props} setmap={setmap} />}
  </context.consumer>
);

for the rest take a look here: demo

score:2

i am not sure how to achieve that using your approach where react-leaflet's wrapper zoomcontrol is not a child of map wrapper when you try to place it outside the map wrapper.

however, for a small control like the zoomcontrol, an easy solution would be to create a custom zoom component, identical to the original, construct it easily using the native css style and after accessing the map element, invoke the zoom in and out methods respectively.

in the below example i use react-context to save the map element after the map loads:

useeffect(() => {
    const map = mapref.current.leafletelement;
    setmap(map);
  }, [mapref, setmap]);

and then here use the map reference to make a custom zoom component identical to the native (for css see the demo):

const zoom = () => {
  const { map } = usecontext(context);

  const zoomin = e => {
    e.preventdefault();
    map.setzoom(map.getzoom() + 1);
  };
  const zoomout = e => {
    e.preventdefault();
    map.setzoom(map.getzoom() - 1);
  };

  return (
    <div classname="leaflet-bar">
      <a
        classname="leaflet-control-zoom-in"
        href="/"
        title="zoom in"
        role="button"
        aria-label="zoom in"
        onclick={zoomin}
      >
        +
      </a>
      <a
        classname="leaflet-control-zoom-out"
        href="/"
        title="zoom out"
        role="button"
        aria-label="zoom out"
        onclick={zoomout}
      >
        −
      </a>
    </div>
  );
};

and then place it wherever you like:

const app = () => {
  return (
    <provider>
      <div style={{ display: "flex", flexdirection: "row" }}>
        <leaflet />
        <zoom />
      </div>
    </provider>
  );
};

demo


Related Query

More Query from same tag