【问题标题】:google maps integration with react js hooks, map flickers on update谷歌地图与反应 js 挂钩的集成,地图在更新时闪烁
【发布时间】: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;

【问题讨论】:

  • 什么时候闪烁?当你关闭信息窗口?
  • 当你改变标记位置时

标签: reactjs react-hooks geocode react-google-maps


【解决方案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 文件并导入,但似乎没有任何效果
猜你喜欢
  • 2015-08-28
  • 1970-01-01
  • 2015-10-07
  • 2020-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
相关资源
最近更新 更多