首页 > 解决方案 > “React 方式”真的是定期重新渲染整个 react-leaflet 组件吗?

问题描述

react-leaflet用来显示带有从 API 加载的动态标记的地图。到目前为止,我一直在渲染中加载标记,但我意识到每次发生任何变化(例如缩放、位置)时,这都会不必要地重新渲染整个传单地图。我想我可以删除我的缩放和位置状态并为此调用本机 Leaflet 函数,但最终我需要在初始渲染后加载我的数据,至少会导致第二次不必要的渲染。React 真的被设计成首选方式吗?

function MyMap() {
  const [markers, setMarkers] = useState([]);

  useEffect(() => {
    console.log('useEffect');

    getMyData().then(a => {
      console.log('data load');
      setMarkers(a);
    });
  }, []);

  console.log('map render');
  return (
    <Map id='map' className='map' center={[52, 0]} zoom={6}>
      <TileLayer
        url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      />
      <LayerGroup>
        {markers.map(a => {
          return (
            <Marker
              key={a._id}
              position={[a.location.latitude, a.location.longitude]}
              icon={myIcon}
            />
          );
        })}
      </LayerGroup>
    </Map>
  );
}

控制台输出:

map render
useEffect
data load
map render

我很想通过以正常的 Leaflet 方式动态添加标记来解决这个问题:

L.marker([50.5, 30.5]).addTo(map);

但这在react-leaflet. 在寻找如何动态添加标记时,我遇到了 React Leaflet:动态添加标记,特别是建议不应该这样做的最佳答案。关联的 jsfiddle 会为每次点击重新渲染整个地图。也许这很好?

标签: react-leaflet

解决方案


为了防止在添加标记后重新渲染地图,可以应用以下更改列表:

a)在状态的MyMap(父)组件中markers跟踪从数据源加载的标记

注意:markers在此组件中单击地图后,状态不会更新

function MyMap() {
  const [markers, setMarkers] = useState([]);

  useEffect(() => {
    console.log("useEffect");
    getMyData().then((data) => {
      console.log("data load");
      setMarkers(data);
    });
  }, []);

  console.log("map render");
  return (
    <Map id="map" className="map" center={[52, 0]} zoom={4}>
      <TileLayer
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      />
      <MyLayer defaultMarkers={markers} />
    </Map>
  );
}

b) 引入一个带有markers状态的单独(子)组件来跟踪从数据源加载的标记(使用通过传递的默认值props设置它)以及在地图click事件上添加的标记:

function MyLayer(props, ref) {
  const { defaultMarkers } = props;
  const [markers, setMarkers] = useState(defaultMarkers);
  const mapProps = useLeaflet();


  const addMarker = useCallback((e) => {
    const newMarker = {
      location: e.latlng,
    };
    console.log(newMarker);
    setMarkers((existingMarkers) => [...existingMarkers, newMarker]);
  }, []);


  useEffect(() => {
    setMarkers(defaultMarkers);  
    mapProps.map.on('click',addMarker)
  }, [addMarker,mapProps,defaultMarkers]);


  return (
    <LayerGroup>
      {markers.map((marker, idx) => {
        return (
          <Marker
            key={idx}
            position={[marker.location.lat, marker.location.lng]}
          />
        );
      })}
    </LayerGroup>
  );
}

这是一个演示


推荐阅读