reactjs - 谷歌地图 API : why does my map state become null?

标签 reactjs google-maps

感谢帮助,我被困住了!

我尝试做什么 我显示带有一组标记的谷歌地图。 当我点击标记时,我想向 map 添加一个 Google 圆圈。

发生了什么 当我单击第一个标记时,没有显示圆圈。 但是当我单击第二个标记和更多标记时,它们就会显示!

为什么不起作用 我已经使用 console.log 跟踪了 map 状态值。 问题是,当我第一次进入 MarkkerClicked 函数时,由于未知原因,“map”状态的值为“null”!所以没有创建任何圆。 而且,更奇怪的是,当第一次加载 map 时以及当我单击第二个标记时, map 状态包含一个 map 实例。

你能告诉我我做错了什么吗?当单击第一个标记时, map 值设置为空?

我的组件:

import { GoogleMap, MarkerF, useJsApiLoader } from "@react-google-maps/api";
import Box from '@mui/material/Box';
import { useSelector } from 'react-redux'

let mapCircle1 = null

export default function MapPage() {
  // The array of markers is in the REDUX store
  const selectMarkersArray = state => state.markersArray
  const markersArray = useSelector(selectMarkersArray)

  // This state contains the selected marker (or null if no marker selected)
  const [selectedMarker, setSelectedMarker] = useState(null);

  // Options for GoogleMaps
  let center = {
      lat: 43.3318,
      lng: 5.0550
  }
  let zoom = 15
  const containerStyle = {
      width: "100%",
      height: "100%"
  }

  // GoogleMaps loading instructions
  const { isLoaded } = useJsApiLoader({
      id: 'google-map-script',
      googleMapsApiKey: "MY-GOOGLE-KEY"
  })
  const [map, setMap] = useState(null)
  const onLoad = useCallback(function callback(map) {
    setMap(map)
    console.log('map value in onLoad :')
    console.log(map)
  }, [])
  const onUnmount = useCallback(function callback(map) {
  setMap(null)
  }, [])

  // Function executed when a marker is clicked
  function markerClicked(props) {
    console.log('map value in markerClicked :')
    console.log(map)

    // I create a new Circle data
    let circleOption1 = {
      fillColor: "#2b32ac ",
      map: map,
      center: {lat:props.marker.spotLatitude, lng:props.marker.spotLongitude},
      radius: props.marker.spotCircleRadius,
    };
    mapCircle1 = new window.google.maps.Circle(circleOption1);

    // I update the selecte marker state
      setSelectedMarker({...props.marker})
    }
    return (isLoaded ? (
      <Box height="80vh" display="flex" flexDirection="column">
        <GoogleMap 
          mapContainerStyle={containerStyle}
          center={center}
          zoom={zoom}                
          onLoad={onLoad}
          onUnmount={onUnmount}
        >
          {markersArray.map((marker, index) => {
            return (
              <MarkerF 
                key={index.toString()} 
                position={{lat:marker.spotLatitude, lng:marker.spotLongitude}}
                onClick={() => markerClicked({marker:marker})}
                >
              </MarkerF>
            )
          })}
        </GoogleMap>
      </Box>
    ) : <></>
  )
};

以及console.log(加载 map 时记录第一个日志,单击第一个标记时记录第二个日志,单击另一个标记时记录第三个日志):

map value in onLoad :
jj {gm_bindings_: {…}, __gm: hda, gm_accessors_: {…}, mapCapabilities: {…}, renderingType: 'UNINITIALIZED', …}

map value in markerClicked :
null

map value in markerClicked :
jj {gm_bindings_: {…}, __gm: hda, gm_accessors_: {…}, mapCapabilities: {…}, renderingType: 'RASTER', …}```

最佳答案

这可能是因为您没有使用 State Hooks 和 <Circle />用于渲染/更新圆圈的组件

我能够在codesandbox上重现您的代码并确认map确实正在返回null每次标记点击。我仍然不确定为什么会发生这种情况,但我设法修复了它,并在通过利用圆圈的 State Hooks 修改代码后,即使在第一次单击标记时也成功渲染了一个圆圈,并且还使用 <Circle />组件按照react-google-maps/api library docs .

我只是设法硬编码了一些东西,因为我没有使用 redux 来重现你的代码,但我所做的一件事是创建一个 circles数组状态 Hook :

  // this array gets updated whenever you click on a marker
  const [circles, setCircles] = useState([
    {
      id: "",
      center: null,
      circleOptions: {
        strokeColor: "#FF0000",
        strokeOpacity: 0.8,
        strokeWeight: 2,
        fillColor: "#FF0000",
        fillOpacity: 0.35,
        clickable: false,
        draggable: false,
        editable: false,
        visible: true,
        radius: 100,
        zIndex: 1
      }
    }
  ]);

只需确保添加 useState关于您的导入。

然后为了演示,我硬编码了一个标记数组:

  // This could be your array of marker using redux,
  // I just hardcoded this for demonstration
  const markersArray = [
    {
      id: 1,
      position: { lat: 43.333194, lng: 5.050184 }
    },
    {
      id: 2,
      position: { lat: 43.336356, lng: 5.053353 }
    },
    {
      id: 3,
      position: { lat: 43.331609, lng: 5.056403 }
    },
    {
      id: 4,
      position: { lat: 43.328806, lng: 5.058998 }
    }
  ];

然后这是我的markerClicked函数看起来像:

// Function executed when a marker is clicked
  const markerClicked = (marker) => {
    console.log("map value on marker click: ");
    console.log(map);
    // This stores the marker coordinates
    // in which we will use for the center of your circle
    const markerLatLng = marker.latLng.toJSON();
    // this will update our circle array
    // adding another object with different center
    // the center is fetched from the marker that was clicked
    setCircles((prevState) => {
      return [
        ...prevState,
        {
          id: "",
          center: markerLatLng,
          circleOptions: {
            strokeColor: "#FF0000",
            strokeOpacity: 0.8,
            strokeWeight: 2,
            fillColor: "#FF0000",
            fillOpacity: 0.35,
            clickable: false,
            draggable: false,
            editable: false,
            visible: true,
            radius: 100,
            zIndex: 1
          }
        }
      ];
    });
    // this is for you to see that the circles array is updated.
    console.log(circles);
  };

请注意 onClick <MarkerF /> 的属性自动返回一个参数,其中包括标记的坐标和其他内容,您可以尝试使用 console.log如果你想检查的话。还要确保您在 onClick 上输入的值等于单独的函数名称。在这种情况下,它是 markerClicked ,稍后您就会看到。

注意:我还添加了 mapClicked函数使您能够清除圆数组。

Please see proof of concept sandbox below.

然后这就是我渲染 <GoogleMap /> 的方式组件 <MarkerF /><Circle />组件作为其子级。

    <GoogleMap
      mapContainerStyle={containerStyle}
      center={center}
      zoom={zoom}
      onLoad={onLoad}
      onUnmount={onUnmount}
      onClick={mapClicked}
    >
      {markersArray.map((marker, index) => {
        return (
          <MarkerF
            key={index.toString()}
            position={{ lat: marker.position.lat, lng: marker.position.lng }}
            onClick={markerClicked}
          ></MarkerF>
        );
      })}
      {/* This maps through the circles array, so when the array gets updated,
       another circle is added */}
      {circles.map((circle, index) => {
        return (
          <Circle
            key={index.toString()}
            // required
            center={circle.center}
            // required
            options={circle.circleOptions}
          />
        );
      })}
    </GoogleMap>

通过所有这些,标记单击时的 map 值不会返回 null,并且即使在第一次标记单击时也会呈现一个圆圈。

这是一个概念验证沙箱,供您检查并了解其工作原理(确保使用您自己的 API key 进行测试):https://codesandbox.io/s/proof-of-concept-show-circle-on-marker-click-s175wl?file=/src/Map.js

Note: There's some weird offset between the marker and the circle if you zoom out too far, but seems fine when you zoom in. I have encountered this on some previous questions here in SO when rendering polylines and I don't know why is that or how to fix it.

话虽如此,希望这会有所帮助!

关于reactjs - 谷歌地图 API : why does my map state become null?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75153679/

相关文章:

javascript - Google Maps API 中的地理编码问题

Android - 如何显示附近的用户标记?

reactjs - 如何使用给定地址初始化 StandaloneSearchBox 组件?

Android:如何在两个 'SplitContainer' 之间创建一个 'Views'

javascript - 你能用 React hooks 提前回来吗?

reactjs - 当用户名和密码正确时, react : How do i make a hidden page, 只能从登录屏幕访问?

css - 使用 React Styled Components 在两种类型的组件之间共享相同的样式

javascript - Visual Studio Code 根据项目更改语言模式

reactjs - Cookie 未存储在浏览器中

javascript - 显示 map 并突出显示某些国家/地区