谷歌地图与反应 js 挂钩的集成,地图在更新时闪烁

Posted

技术标签:

【中文标题】谷歌地图与反应 js 挂钩的集成,地图在更新时闪烁【英文标题】:google maps integration with react js hooks, map flickers on update 【发布时间】:2021-09-27 01:34:20 【问题描述】:

所以我正在做一个项目,我想集成谷歌地图,所以我下载了这些包(反应地理代码和反应谷歌地图)我阅读了他们的文档并在代码沙箱上找到了一段代码来帮助我解决问题通过集成地图,我将代码从类重构为钩子,但是当使用类组件时,地图在更新位置标记时不会闪烁,但是当我更新到钩子时,当我更改位置标记时它开始闪烁,是我的代码还是我的代码重构遗漏任何东西,或者是如何使用钩子管理状态,这使得闪烁不可避免 下面是更新的代码,这是原始代码 (https://codesandbox.io/s/modest-platform-g8mjx?file=/src/LocationSearchModal.js) 知道为什么我有 2 个标记吗?

import React,  useCallback, useEffect, useState  from "react";
import 
  withGoogleMap,
  GoogleMap,
  withScriptjs,
  InfoWindow,
  Marker
 from "react-google-maps";
import Geocode from "react-geocode";
import Autocomplete from "react-google-autocomplete";
import  Card  from "react-bootstrap";

Geocode.setApiKey("googleAPIKEYHERE");
Geocode.enableDebug();

const LocationSearchModal = () => 
  const [state, setState] = useState(
    address: "",
    city: "",
    area: "",
    state: "",
    zoom: 15,
    height: 400,
    mapPosition: 
      lat: 55,
      lng: 55
    ,
    markerPosition: 
      lat: 55,
      lng: 55
    
  );

  const getCity = useCallback((addressArray) => 
    let city = "";
    for (let i = 0; i < addressArray.length; i++) 
      if (
        addressArray[i].types[0] &&
        "administrative_area_level_2" === addressArray[i].types[0]
      ) 
        city = addressArray[i].long_name;
        return city;
      
    
  , []);

  const getArea = useCallback((addressArray) => 
    let area = "";
    for (let i = 0; i < addressArray.length; i++) 
      if (addressArray[i].types[0]) 
        for (let j = 0; j < addressArray[i].types.length; j++) 
          if (
            "sublocality_level_1" === addressArray[i].types[j] ||
            "locality" === addressArray[i].types[j]
          ) 
            area = addressArray[i].long_name;
            return area;
          
        
      
    
  , []);

  const getState = useCallback((addressArray) => 
    let state = "";
    for (let i = 0; i < addressArray.length; i++) 
      for (let i = 0; i < addressArray.length; i++) 
        if (
          addressArray[i].types[0] &&
          "administrative_area_level_1" === addressArray[i].types[0]
        ) 
          state = addressArray[i].long_name;
          return state;
        
      
    
  , []);

  const onChange = (event) => 
    setState( [event.target.name]: event.target.value );
  ;

  const onInfoWindowClose = (event) => ;

  const onMarkerDragEnd = useCallback((event) => 
    const newLat = event.latLng.lat(),
      newLng = event.latLng.lng();

    setState((prev) => (
      ...prev,
      mapPosition: 
        lat: newLat,
        lng: newLng
      ,
      markerPosition: 
        lat: newLat,
        lng: newLng
      
    ));
    Geocode.fromLatLng(newLat, newLng).then(
      (response) => 
        //     const address = response.results[0].formatted_address,
        //       addressArray = response.results[0].address_components,
        //       city = getCity(addressArray),
        //       area = getArea(addressArray),
        //       state = getState(addressArray);
        console.log(response);
        const address = response.results[0].formatted_address;
        let city, state, area;
        for (
          let i = 0;
          i < response.results[0].address_components.length;
          i++
        ) 
          for (
            let j = 0;
            j < response.results[0].address_components[i].types.length;
            j++
          ) 
            switch (response.results[0].address_components[i].types[j]) 
              case "locality":
                city = response.results[0].address_components[i].long_name;
                break;
              case "administrative_area_level_1":
                state = response.results[0].address_components[i].long_name;
                break;
              case "country":
                area = response.results[0].address_components[i].long_name;
                break;
            
          
        
        setState((prev) => (
          ...prev,
          address: address ? address : "",
          area: area ? area : "",
          city: city ? city : "",
          state: state ? state : ""
        ));
      ,
      (error) => 
        console.error(error);
      
    );
  , []);

  const onPlaceSelected = useCallback(
    (place) => 
      console.log("plc", place);
      const address = place.formatted_address,
        addressArray = place.address_components,
        city = getCity(addressArray),
        area = getArea(addressArray),
        state = getState(addressArray),
        latValue = place.geometry.location.lat(),
        lngValue = place.geometry.location.lng();

      console.log("latvalue", latValue);
      console.log("lngValue", lngValue);

      // Set these values in the state.
      setState((prev) => (
        address: address ? address : "",
        area: area ? area : "",
        city: city ? city : "",
        state: state ? state : "",
        markerPosition: 
          lat: latValue,
          lng: lngValue
        ,
        mapPosition: 
          lat: latValue,
          lng: lngValue
        
      ));
    ,
    [getArea, getCity, getState]
  );

  const AsyncMap = withScriptjs(
    withGoogleMap((props) => 
      console.log(props);
      return (
        <GoogleMap
          defaultZoom=state.zoom
          defaultCenter=
            lat: state.markerPosition.lat,
            lng: state.markerPosition.lng
          
        >
          /*Marker*/
          <Marker
            google=window.google
            name="Dolores park"
            draggable=true
            onDragEnd=onMarkerDragEnd
            position=
              lat: state.markerPosition.lat,
              lng: state.markerPosition.lng
            
          />
          <InfoWindow
            onClose=onInfoWindowClose
            position=
              lat: state.markerPosition.lat,
              lng: state.markerPosition.lng
            
          >
            <div>
              <span style= padding: 0, margin: 0 >state.address</span>
            </div>
          </InfoWindow>
          <Marker />

          /* <MarkerWithLabel
                            position= lat: -34.397, lng: 150.644 
                            labelAnchor=new google.maps.Point(0, 0)
                            labelStyle= backgroundColor: "yellow", fontSize: "32px", padding: "16px" 
                        >
                            <div>Hello There!</div>
                        </MarkerWithLabel> */

          /* For Auto complete Search Box */
          <Autocomplete
            style=
              width: "100%",
              height: "40px",
              paddingLeft: "16px",
              marginTop: "2px",
              marginBottom: "2rem"
            
            onPlaceSelected=onPlaceSelected
            types=["(regions)"]
          />
        </GoogleMap>
      );
    )
  );

  useEffect(() => 
    let _isMounted = true;
    function fetchLocation() 
      try 
        Geocode.fromLatLng(state.mapPosition.lat, state.mapPosition.lng).then(
          (response) => 
            const address = response.results[0].formatted_address,
              addressArray = response.results[0].address_components,
              city = getCity(addressArray),
              state = getState(addressArray),
              area = getArea(addressArray);

            setState((prev) => (
              ...prev,
              address: address ? address : "",
              city: city ? city : "",
              area: area ? area : ""
            ));
          
        );
       catch (e) 
        console.error(e);
      
    
    fetchLocation();
    return () => 
      _isMounted = false;
    ;
  , [getArea, getCity, getState]);

  
  return (
    <div style= padding: "1rem", margin: "0 auto", maxWidth: 1000 >
      <h1>Campus Guide Routes</h1>
      <Card bordered>
        <Card.Text label="City">state.city</Card.Text>
        <Card.Text label="Area">state.area</Card.Text>
        <Card.Text label="State">state.state</Card.Text>
        <Card.Text label="Address">state.address</Card.Text>
      </Card>

      <AsyncMap
        googleMapURL="https://maps.googleapis.com/maps/api/js?key=googleApiKeyHere&libraries=places"
        loadingElement=<div style= width: "100%", height: `100%`  />
        containerElement=
          <div style= width: "100%", height: state.height  />
        
        mapElement=<div style= width: "100%", height: `100%`  />
      />
    </div>
  );
;

export default LocationSearchModal;

【问题讨论】:

什么时候闪烁?当你关闭信息窗口? 当你改变标记位置时 【参考方案1】:

试试这个,

const AsyncMap = withScriptjs(
        withGoogleMap((props) => 
          return (
            <GoogleMap
              defaultZoom=state.zoom
              defaultCenter=
                lat: state.markerPosition.lat,
                lng: state.markerPosition.lng
              
             id="map-container"
            >
    .....

将 css 添加到地图容器

#map-container 
  overflow-anchor:none;

【讨论】:

不幸的是我之前没有在 react 中使用 ids,我是否创建一个文件并像这样导入它从 "../../../../../src/资产/scss/test.css";然后使用这个 id=styles["map-container"] 并知道为什么我有 2 个标记 确保 css 将根据您的代码结构应用于您的代码 我将 css 添加到 css 文件并导入,但似乎没有任何效果

以上是关于谷歌地图与反应 js 挂钩的集成,地图在更新时闪烁的主要内容,如果未能解决你的问题,请参考以下文章

谷歌地图 api 与 jquery 幻灯片的集成存在动画故障

在本机反应中打开地图/谷歌地图

在反应原生中链接谷歌地图应用程序时如何呈现方向?

未使用的 div 出现在反应谷歌地图上,我无法设置它的样式

颤动谷歌地图在运行时更新地图样式

谷歌地图根本无法与 Meteor 一起使用 - iOS