向DrawFToolbar传递Map作为Props后调用方法报错问题排查
为什么Leaflet Map的方法在子组件中无法调用?
你遇到的问题是:将Map组件中的map以props传入DrawFToolbar后,控制台能打印出map对象,但调用map.addLayer(或addTo(map))时会报错map.addLayer is not a function,尽管看起来map是有效的实例。
问题代码
Map组件
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 © <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
DrawFToolbar组件
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;
问题根源
你传递给DrawFToolbar的mapRef.current是DOM元素(即承载地图的div),而不是Leaflet创建的map实例。Leaflet的addTo()方法需要接收的是Leaflet Map对象,而不是DOM节点,所以才会报错map.addLayer is not a function。
解决方案
在Map组件中单独存储Leaflet的map实例,然后将这个实例传递给子组件:
- 在Map组件中新增一个ref用于存储Leaflet map实例
- 将该实例作为props传给DrawFToolbar,而不是DOM元素的ref
修改后的Map组件
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); // 新增ref存储Leaflet map实例 const mapInstanceRef = useRef(null); const [drawToolbarLoaded, setDrawToolbarLoaded] = useState(false); useEffect(() => { if (mapRef.current) { const map = L.map(mapRef.current).setView([51.505, -0.09], 13); // 将map实例存入ref mapInstanceRef.current = map; L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors', maxZoom: 18, }).addTo(map); setDrawToolbarLoaded(true); return () => { map.remove(); // 清空实例ref mapInstanceRef.current = null; } } }, []); return ( <div ref={mapRef} style={{ height: '400px' }} > {/* 传递map实例给子组件 */} {drawToolbarLoaded && <DrawFToolbar map={mapInstanceRef.current} />} </div> ); } export default Map
修改后的DrawFToolbar组件
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.map; console.log(map); if (map) { L.marker([51.6, -0.09]).addTo(map); } }, [props.map]); return null; } export default DrawFToolbar;
这样修改后,子组件接收的是真正的Leaflet Map实例,调用addTo(map)或其他Map方法就不会报错了。
内容的提问来源于stack exchange,提问作者ehsanpaknahad
相关产品推荐
相关产品推荐

