6

我有一个使用https://github.com/tomchentw/react-google-maps的非常简单的反应应用程序,但我很难理解如何获取对我当前地图的引用或如何访问google.maps.Map自定义组件中的对象。

我在 repo 上找到了这个,但是在阅读了这些帖子后,我仍然有点困惑。

我正在从DirectionsRenderer示例开始构建我的应用程序。

我接下来要做的是添加我自己的自定义组件来选择起点并使用 Google Maps 自动完成 API。

是的,我知道这个包已经有一个组件,但我需要做的不仅仅是在地图上搜索一个位置。

为了满足我的需求,我会做类似的事情

const autocomplete = new google.maps.places.Autocomplete(node);
autocomplete.bindTo('bounds', map);

node我绑定自动完成功能的元素在哪里,并且mapgoogle.maps.Map对象的一个​​实例。

到目前为止我的申请:

应用程序.jsx

const App = ({ store }) => (
  <Provider store={store}>
    <div>
      <Sidebar>
        <StartingPoint defaultText="Choose starting point&hellip;" />
      </Sidebar>
      <GoogleApiWrapper />
    </div>
  </Provider>
);

GoogleApiWrapper

const GoogleMapHOC = compose(
  withProps({
    googleMapURL: 'https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=__GAPI_KEY',
    loadingElement: <div style={{ height: '100vw' }} />,
    containerElement: <div style={{ height: '100vh' }} />,
    mapElement: <div style={{ height: '100%' }} />,
  }),
  withScriptjs,
  withGoogleMap,
  lifecycle({
    componentDidMount() {
      const DirectionsService = new google.maps.DirectionsService();

      // make google object available to other components
      this.props.onLoad(google);

      DirectionsService.route({
        origin: new google.maps.LatLng(41.8507300, -87.6512600),
        destination: new google.maps.LatLng(41.8525800, -87.6514100),
        travelMode: google.maps.TravelMode.DRIVING,
      }, (result, status) => {
        if (status === google.maps.DirectionsStatus.OK) {
          this.setState({
            directions: result,
          });
        } else {
          console.error(`error fetching directions ${result}`);
        }
      });
    },
  }),
)(props => (
  <GoogleMap
    ref={props.onMapMounted}
    defaultZoom={13}
    defaultCenter={new google.maps.LatLng(37.771336, -122.446615)}
  >
    {props.directions && <DirectionsRenderer directions={props.directions} />}
  </GoogleMap>
));

如果我无法访问google.maps.Map包装器之外的对象,我也想访问对包含地图的元素的引用,以便我可以实例化一个new google.maps.Map(ref_to_elem, options);

任何帮助将不胜感激!

4

5 回答 5

11

你可以通过 React refs 来做到这一点:

<GoogleMap ref={(map) => this._map = map} />
function someFunc () { 
    //using, for example as:
    this._map.getCenter() 
    this._map.setZoom(your desired zoom);
}
于 2017-12-18T18:44:45.077 回答
1

我现在在我的 react-redux 应用程序中所做的是在反应组件 GoogleMap 之外分配全局变量映射:

/*global google*/

// your imports //

var map;

class GoogleMap extends Component {
  constructor(props) {
    super(props);

    this.state = {
      // your states
    };
  }

  // your functions

  componentWillReceiveProps(nextProps) {

  }

  componentDidMount() {

    // code

    // render googlemap

    map = new google.maps.Map(this.refs.map, yourMapProps);

    // add click event listener to the map

    map.addListener('click', function(e) {
      //code
    });

    //viewport listener

    map.addListener('idle', function(){
      // code
    });
  }

  render() {
      return (
        <div id="map" ref="map">
          {places.map((place) => {
             return(<Marker place={place} key={place.key} map={map} />);
          })}
        </div>
  }
}

function mapDispatchToProps(dispatch) {
   //code
}

export default connect(mapDispatchToProps)(GoogleMap);

将地图作为道具传递给子组件:

/*global google*/

import React, { Component } from 'react';

class Marker extends Component {
  componentDidMount() {
    this.renderMarker();
  }

  renderMarker() {
    var { place, map } = this.props;
    place.setMap(map);
  }

  render() {
    return null;
  }
}

export default Marker;

我不知道这是一个好习惯。但它有效。我试图找到解决方案如何避免将 Map Object 设置为全局 windows.map 阅读所有关于单例的东西等等。然后我想到了这个。现在,如果我在浏览器 concole 中键入 window.map,我会得到 div id="map"

于 2018-01-17T05:42:08.577 回答
1
import {GoogleMap, withGoogleMap} from 'react-google-maps';
import {MAP} from 'react-google-maps/lib/constants';

const MapComponent = withGoogleMap(() => (
 {/*Here you have access to google.maps.Map object*/}
     <GoogleMap ref={(map) => map.context[MAP]}/>
 ));


const Map = ({locations}) => (
  <MapComponentClass
    containerElement={MapComponent}
    mapElement={MapComponent}
    locations={locations}/>
);

export default Map;
于 2019-07-24T14:08:14.090 回答
1

值得指出的是,现在其他任何人在谷歌上搜索这个,使用react-google-maps你可以简单地使用useGoogleMap钩子来访问谷歌地图实例

https://react-google-maps-api-docs.netlify.app/#map-instance

import React from 'react'
import { useGoogleMap } from '@react-google-maps/api'

function PanningComponent() {
  const map = useGoogleMap()

  React.useEffect(() => {
    if (map) {
      map.panTo(...)
    }
  }, [map])

  return null
}
于 2021-06-21T00:05:21.837 回答
0

在彻底阅读 react-google-maps 文档、示例和问题后,我了解到该软件包不支持我需要为我的应用程序做的很多事情。

话虽如此,我已经开始根据Fullstack React所做的工作编写自己的 Google Maps API 包装器。我省略了下面提到的许多实用程序,因为它们可以在此处此处找到。

话虽如此,我的解决方案是将谷歌地图容器包装在更高阶的组件中,并Map通过对象公开window对象:

应用程序

const App = ({ store }) => (
  <Provider store={store}>
    <div>
      <Sidebar>
        <StartingPoint />
        {/* TODO */}
      </Sidebar>
      <GoogleMap />
    </div>
  </Provider>
);

container/GoogleMap/wrapper.jsx谷歌地图高阶组件包装了谷歌地图容器

const defaultCreateCache = (options) => {
  const opts = options || {};
  const apiKey = opts.apiKey;
  const libraries = opts.libraries || ['places'];
  const version = opts.version || '3.24';
  const language = opts.language || 'en';

  return ScriptCache({
    google: GoogleApi({
      apiKey,
      language,
      libraries,
      version,
    }),
  });
};

const wrapper = options => (WrappedComponent) => {
  const createCache = options.createCache || defaultCreateCache;

  class Wrapper extends Component {
    constructor(props, context) {
      super(props, context);

      this.scriptCache = createCache(options);
      this.scriptCache.google.onLoad(this.onLoad.bind(this));

      this.state = {
        loaded: false,
        google: null,
      };
    }

    onLoad() {
      this.GAPI = window.google;

      this.setState({ loaded: true, google: this.GAPI });
    }

    render() {
      const props = Object.assign({}, this.props, {
        loaded: this.state.loaded,
        google: window.google,
      });
      const mapRef = (el) => { this.map = el; };

      return (
        <div>
          <WrappedComponent {...props} />
          <div ref={mapRef} />
        </div>
      );
    }
  }
  Wrapper.propTypes = {
    dispatchGoogleAPI: PropTypes.func,
  };
  Wrapper.defaultProps = {
    dispatchGoogleAPI: null,
  };

  return Wrapper;
};

export default wrapper;

container/GoogleMap/index.jsx谷歌地图容器

class Container extends Component {
  constructor(props) {
    super(props);

    this.loadMap = this.loadMap.bind(this);
    this.calcRoute = this.calcRoute.bind(this);
  }

  componentDidUpdate() {
    const { origin, destination, route } = this.props;

    this.calcRoute(origin, destination);
  }

  loadMap(node) {
    if (this.props && this.props.google) {
      const { google } = this.props;

      // instantiate Direction Service
      this.directionsService = new google.maps.DirectionsService();

      this.directionsDisplay = new google.maps.DirectionsRenderer({
        suppressMarkers: true,
      });

      const zoom = 13;
      const mapTypeId = google.maps.MapTypeId.ROADMAP;
      const lat = 37.776443;
      const lng = -122.451978;
      const center = new google.maps.LatLng(lat, lng);

      const mapConfig = Object.assign({}, {
        center,
        zoom,
        mapTypeId,
      });

      this.map = new google.maps.Map(node, mapConfig);

      this.directionsDisplay.setMap(this.map);

      // make the map instance available to other components
      window.map = this.map
    }
  }

  calcRoute(origin, destination) {
    const { google, route } = this.props;

    if (!origin && !destination && !route) return;

    const waypts = [];

    waypts.push({
      location: new google.maps.LatLng(37.415284, -122.076899),
      stopover: true,
    });

    const start = new google.maps.LatLng(origin.lat, origin.lng);
    const end = new google.maps.LatLng(destination.lat, destination.lng);

    this.createMarker(end);

    const request = {
      origin: start,
      destination: end,
      waypoints: waypts,
      optimizeWaypoints: true,
      travelMode: google.maps.DirectionsTravelMode.DRIVING,
    };

    this.directionsService.route(request, (response, status) => {
      if (status === google.maps.DirectionsStatus.OK) {
        this.directionsDisplay.setDirections(response);
        const route = response.routes[0];
        console.log(route);
      }
    });

    this.props.calculateRoute(false);
  }

  createMarker(latlng) {
    const { google } = this.props;

    const marker = new google.maps.Marker({
      position: latlng,
      map: this.map,
    });
  }

  render() {
    return (
      <div>
        <GoogleMapView loaded={this.props.loaded} loadMap={this.loadMap} />
      </div>
    );
  }
}

const GoogleMapContainer = wrapper({
  apiKey: ('YOUR_API_KEY'),
  version: '3', // 3.*
  libraries: ['places'],
})(Container);

const mapStateToProps = state => ({
  origin: state.Trip.origin,
  destination: state.Trip.destination,
  route: state.Trip.route,
});

const mapDispatchToProps = dispatch => ({
  dispatchGoogleMap: (map) => {
    dispatch(googleMap(map));
  },
  calculateRoute: (route) => {
    dispatch(tripCalculation(route));
  },
});

const GoogleMap = connect(mapStateToProps, mapDispatchToProps)(GoogleMapContainer);

export default GoogleMap;
于 2017-09-18T03:27:47.367 回答