【问题标题】:Show All Cluster Markers in react-leaflet-markerclusterer using React Typescript使用 React Typescript 在 react-leaflet-markerclusterer 中显示所有集群标记
【发布时间】:2021-05-21 01:02:00
【问题描述】:

我的 React Typescript 应用正在使用 react-leafletreact-leaflet-markerclusterer 显示带有标记集群的传单地图。

但是,我无法让地图显示地图视图内的所有集群标记。我正在尝试 convert this JS solution 到 Typescript。

中显示的错误之一。 JS 控制台是

无法在回调中调用 React Hook “useMap”。 React Hooks 必须在 React 函数组件或自定义 React Hook 函数中调用

在VSCode中,也存在Typescript错误

对象可能是'未定义'.ts(2532)

上线

const groupBounds = group.getBounds();

为什么会发生这种情况,编写此 Typescript 代码的正确方法是什么?

import React, { useEffect, useRef } from 'react';
import { MapContainer, TileLayer, Marker, useMap } from 'react-leaflet';
import MarkerClusterGroup from 'react-leaflet-markercluster';

interface IProps {
    markers: {
        lat: number;
        lon: number;
    }[];
    
    mapCenter: {
        lat: number;
        lon: number;
    };
}

export function MapView({markers, mapCenter}: IProps): JSX.Element {

    const groupRef = useRef();
    
    useEffect(() => {
        if (groupRef !== undefined) {
            const group = groupRef.current;
            const map = useMap();                   // ERROR: React Hook "useMap" cannot be called inside a callback.
            const groupBounds = group.getBounds();  // ERROR: Object is possibly 'undefined'.ts(2532)
            map.fitBounds(groupBounds);
        }
    }, []);

    return (
        <MapContainer
            center={[mapCenter.lat, mapCenter.lon]}
            zoom={10}
            style={{ width:'100%', height:'100vh' }}
            className='markercluster-map'
        >
            <TileLayer 
                url={`https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=${access_token}`}
            />
            <MarkerClusterGroup ref={groupRef}>
                {
                    markers.map((marker, index) => (
                        <Marker 
                            position={[marker.lat, marker.lon]} 
                            key={index}
                        />
                    ))
                }
            </MarkerClusterGroup>
        </MapContainer>
    )
}

【问题讨论】:

    标签: javascript reactjs typescript leaflet react-leaflet


    【解决方案1】:

    这不是打字稿问题,这是反应问题。挂钩need to be called either within the top level of the function body, or as part of another custom hook。这同样适用于 react-leaflet 的 useMap。您可以将其移到useEffect 之外。但是,useMap 钩子调用必须是作为MapContainer 子组件的组件的一部分,以便它可以访问传单上下文对象。您可以将此逻辑抽象到它自己的组件中,例如在this example 中,但我认为您最好使用带有状态变量的whenCreated 来获取L.Map 的实例并在效果中使用它:

    export function MapView({markers, mapCenter}: IProps): JSX.Element {
    
        const groupRef = useRef();
        const [map, setMap] = useState();
    
        useEffect(() => {
            if (groupRef && map) {
                const group = groupRef.current;
                const groupBounds = group?.getBounds();
                map.fitBounds(groupBounds);
            }
        }, [map, groupRef]);
    
        return (
            <MapContainer
              whenCreated={map => setMap(map)}
              moreProps={moreProps}
            >
               <Stuff />
            </MapContainer>
        )
    
    }
    

    如果 TS 仍然抱怨 groupmap 未定义,您可以对它们使用可选的属性运算符 ?.

    if (groupRef && map) {
      const group = groupRef?.current;
      const groupBounds = group?.getBounds();
      map?.fitBounds(groupBounds);
    }
    

    Typescript 应该足够聪明,可以知道 groupRefmap 已定义,因为它们在 if 语句中,但它可能仍会抱怨 group 已定义。您也可以使用if (groupRef &amp;&amp; groupRef.current &amp;&amp; map) 来消除所有疑问。

    **注意:确保您使用与 react-leaflet v3 兼容的正确 version of react-leaflet-markercluster

    【讨论】:

    • 谢谢,使用whenCreated 对我来说很棒。
    猜你喜欢
    • 1970-01-01
    • 2012-05-17
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 2020-08-21
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    相关资源
    最近更新 更多