Search code examples
javascriptreactjsleaflet

map as props in DrawFToolbar does not work correctly


i tried to simplified my codes to get sooner a solution, I have a Map component and a DrawFToolbar component, I send map as props to DrawFToolbar component, there are some console lines in DrawFToolbar to check.so in console I get this messages: "DrawFToolbar rendered" and "DrawFToolbar useEffect hook triggered" and then map send to console, it seems to be a valid map element () but when compiler reach to run any method of map , i get this error: "map.addLayer is not a function" . for example i want to add a marker to map and get mentioned error. following i put my codes it make easy solving this error :

import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import 'leaflet-draw/dist/leaflet.draw.css';
import 'leaflet-toolbar/dist/leaflet.toolbar.css';
import 'leaflet-draw/dist/leaflet.draw.js';
import 'leaflet-toolbar/dist/leaflet.toolbar.js';
import React, { useState, useEffect, useRef } from 'react';
import Axios from "axios";
import  DrawFToolbar from './DrawFToolbar';
import 'leaflet-toolbar';

 
function Map() {
  const mapRef = useRef(null);  
  const [drawToolbarLoaded, setDrawToolbarLoaded] = useState(false);

  useEffect(() => {

    if (mapRef.current) {
    const map = L.map(mapRef.current).setView([51.505, -0.09], 13);

    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors',
      maxZoom: 18,
    }).addTo(map);
  

    setDrawToolbarLoaded(true);
  
   return () => {
      map.remove();
    }
  }
  
  }, []);

  
  return (<div ref={mapRef} style={{ height: '400px' }} > 
            {drawToolbarLoaded && <DrawFToolbar mapRef={mapRef} />}
          </div>);
  
}

export default Map

import { useEffect } from 'react';
import L from 'leaflet';
import 'leaflet-draw/dist/leaflet.draw.css';
import 'leaflet-toolbar/dist/leaflet.toolbar.css';
import 'leaflet-draw/dist/leaflet.draw.js';
import 'leaflet-toolbar/dist/leaflet.toolbar.js';
import 'leaflet/dist/leaflet.css';


function DrawFToolbar(props) {

  console.log('DrawFToolbar rendered');
  useEffect(() => {
     
    console.log('DrawFToolbar useEffect hook triggered');
    const map = props.mapRef.current;
    
    console.log(map)
      if (map) {
      L.marker([51.6, -0.09]).addTo(map);
    }
  
  }, [props.mapRef]);

  return null;
   
}

export default DrawFToolbar;

I expect to know why leaflet map's methods in DrawFToolbar do not work whereas map exist and apparently is a valid leaflet map. thanks


Solution

  • The map needed for .addTo(map) is NOT the map container DOM Element (stored here in mapRef), but the JS object returned by Leaflet L.map() factory:

    const map = L.map(mapRef.current)
    //    ^-- This object
    

    (The same that you use for map.remove())

    So in your case you could simply store that object in another React ref, to provide it to your <DrawFToolbar> Component:

    function Map() {
      /** ref for the DOM Element */
      const mapContainerRef = useRef(null);
      /** ref for the Leaflet JS object */
      const mapObjectRef = useRef();
      
      useEffect(() => {
        if (mapContainerRef.current) {
          const map = L.map(mapContainerRef.current);
          // Store it in its own ref
          mapObjectRef.current = map;
      
          return () => {
            map.remove();
          };
        }
      }, []);
    
      return (
        <div ref={mapContainerRef}> 
          <DrawFToolbar mapRef={mapObjectRef} />
        </div>
      );
    }