I am new to react and I try to pass two location coordinates from a functional component to a class component. This is the way that I try to pass data to the class component.
function ViewPost() {
console.log(posts);
const long = posts?.location?.longitude;
console.log(long);
const lat=posts?.location?.latitude;
console.log(lat);
const location=[lat,long];
return(
<SimpleMap loc={location}/>
);
}
export default ViewPost;
In the class component,
const AnyReactComponent = ({ text }) => <div>{text}</div>;
class SimpleMap extends Component {
static defaultProps = {
center: {
lat: 59.95,
lng: 30.33
},
zoom: 11
};
render() {
const {lat, long}=this.props.loc;
console.log(lat);
console.log(long);
return (
<div className="location-box-b" style={{ height: '100vh', width: '100%' }}>
<GoogleMapReact
bootstrapURLKeys={{ key: "" }}
defaultCenter={this.props.center}
defaultZoom={this.props.zoom}
>
<AnyReactComponent
lat={this.props.loc.lat}
lng={this.props.loc.long}
text="Seller's Location"
/>
</GoogleMapReact>
</div>
);
}
}
export default SimpleMap;
This is the code that I try to get data from the functional component. When I try to do like this
const {lat, long}=this.props.loc;
console.log(lat);
console.log(long);
print 'undefined' in the console. How do I solve this error?
Your this.props.loc is an array, this is how you defined it here
const location=[lat,long];
but you are trying to get properties from it like from object
const {lat, long}=this.props.loc;
so you have to change it to be an object:
const location={lat,long};
Related
I have a google map approach that map itself isn't showing, I have 2 pieces of code the first is Map component itself, that's the code for it:
import React, {
useState,
useEffect,
useRef
} from 'react';
interface MapProps extends google.maps.MapOptions {
style: { [key: string]: string };
onClick?: (e: google.maps.MapMouseEvent) => void;
onIdle?: (map: google.maps.Map) => void;
children?: React.ReactNode;
}
const Map: React.FC<MapProps> = ({
onClick,
onIdle,
children,
style,
...options
}) => {
const MyStyle = {
width: '100%',
height: '600px'
}
const ref = useRef<HTMLDivElement>(null);
const [map, setMap] = useState<google.maps.Map>();
return (
<>
<div ref={ref} />
</>
)
}
export default Map;
The second component is App component, the one which Map is being rendered, its code is:
import Map from './components/mapComponent2';
import {
Wrapper,
Status
} from '#googlemaps/react-wrapper';
function App = () => {
const center = { lat: 30.033333, lng: 31.233334 };
const zoom = 5;
useEffect(() => {
if (ref.current && !map) {
setMap(new window.google.maps.Map(ref.current, {}));
}
if (map) {
["click", "idle"].forEach((eventName) =>
google.maps.event.clearListeners(map, eventName)
);
if (onClick) {
map.addListener("click", onClick);
}
if (onIdle) {
map.addListener("idle", () => onIdle(map));
}
}
}, [ref, map, onClick, onIdle]);
return(
<div className='App'>
<Wrapper apiKey={API_KEY} libraries={['places', 'drawing', 'geometry']}>
<Map
center={center}
onClick={onMapClick}
onIdle={onIdle}
zoom={zoom}
style={{ flexGrow: "1", height: '600px' }}
/>
</Wrapper>
</div>
)
}
export default App;
after giving the inner div the proper height and width the map element appears inside inner div but the element itself isn't showing, although all click handlers related to the map are working. Can any anyone help me to determine where's the problem?
I am trying to use google-map-react library to locate the user's current location on Google Maps. I managed to use react-geolocated to get coordinates and fed them into the Latitude and Longitude props in the GoogleMapReact component but it was very far from accurate. I am now seeking an alternative on how to use Google Maps API to get more accurate coordinates and focus on the area on a map where the user is located. Using handleApiLoaded method which I failed to understand how to use to achieve this.
Below is some of the code that I wrote to try and solve this
import React from "react";
import GoogleMapReact from "google-map-react";
import { geolocated } from "react-geolocated";
import LocateMeButton from "./Button";
import "./App.css";
const Marker = () => (
<img
src={
"http://icons.iconarchive.com/icons/paomedia/small-n-flat/256/map-marker-icon.png"
}
alt="MyPin"
/>
);
const Map = props => {
const [state, stateUpdater] = React.useState({
lat: "",
lng: "",
text: ""
});
const getGeolocationCordinates = () => {
return !props.isGeolocationAvailable
? stateUpdater({ text: "unsupported browser" })
: !props.isGeolocationEnabled
? stateUpdater({ text: "Geolocation not enabled" })
: props.coords
? stateUpdater({
lng: props.coords.longitude,
lat: props.coords.latitude
})
: "Getting the location";
};
return (
<div className=" map-container">
<LocateMeButton Click={() => getGeolocationCordinates()} />
<GoogleMapReact
bootstrapURLKeys={{
key: "API_KEY",
language: "en"
}}
yesIWantToUseGoogleMapApiInternals
defaultCenter={{ lat: 0.3211264, lng: 32.5910528 }}
defaultZoom={11}
>
<Marker lat={state.lat} lng={state.lng} />
</GoogleMapReact>
</div>
);
};
export default geolocated({
positionOptions: {
enableHighAccuracy: true
},
userDecisionTimeout: 5000
})(Map);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!-- end snippet -->
import React from "react";
import GoogleMapReact from "google-map-react";
import { geolocated } from "react-geolocated";
import LocateMeButton from "./Button";
import "./App.css";
const Marker = () => (
<img
src={
"http://icons.iconarchive.com/icons/paomedia/small-n-flat/256/map-marker-icon.png"
}
alt="MyPin"
/>
);
const Map = props => {
const [state, stateUpdater] = React.useState({
lat: "",
lng: "",
text: ""
});
const getGeolocationCordinates = () => {
return !props.isGeolocationAvailable
? stateUpdater({ text: "unsupported browser" })
: !props.isGeolocationEnabled
? stateUpdater({ text: "Geolocation not enabled" })
: props.coords
? stateUpdater({
lng: props.coords.longitude,
lat: props.coords.latitude
})
: "Getting the location";
};
return (
<div className=" map-container">
<LocateMeButton Click={() => getGeolocationCordinates()} />
<GoogleMapReact
bootstrapURLKeys={{
key: "AIzaSyBtgM1mf0N-Pcsko7Dc5Q2La-K460a9IsA",
language: "en"
}}
yesIWantToUseGoogleMapApiInternals
defaultCenter={{ lat: 0.3211264, lng: 32.5910528 }}
defaultZoom={11}
>
<Marker lat={state.lat} lng={state.lng} />
</GoogleMapReact>
</div>
);
};
export default geolocated({
positionOptions: {
enableHighAccuracy: true
},
userDecisionTimeout: 5000
})(Map);
I removed the API key that you included in your question. In the future, make sure that you won't post your API key in a public site to protect it.
You can implement this use case using your browser's HTML5 Geolocation feature along with the Maps JavaScript API.
Here is a sample code and code snippet below that implements this in google-map-react library.
import React, { Component } from "react";
import GoogleMapReact from "google-map-react";
import "./style.css";
class GoogleMaps extends Component {
constructor(props) {
super(props);
this.state = {
currentLocation: { lat: 40.756795, lng: -73.954298 }
};
}
render() {
console.log(this.state.inputRad);
const apiIsLoaded = (map, maps) => {
navigator?.geolocation.getCurrentPosition(
({ coords: { latitude: lat, longitude: lng } }) => {
const pos = { lat, lng };
this.setState({ currentLocation: pos });
}
);
};
return (
<div>
<div style={{ height: "400px", width: "100%" }}>
<GoogleMapReact
bootstrapURLKeys={{
key: "YOUR_API_KEY",
libraries: ["places"]
}}
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={10}
center={this.state.currentLocation}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => apiIsLoaded(map, maps)}
/>
</div>
</div>
);
}
}
export default GoogleMaps;
Hi folks I'm using the react-google-maps library. I'm trying to recenter my map (zoom where the marker is) every time my location changes, but I'm getting a bit lost on how to implement the whole thing. I can see the marker being updated, but the map stays on its defaultCenter position.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
GoogleMap,
Marker,
withScriptjs,
withGoogleMap
} from 'react-google-maps';
import environment from '../../config/environment';
class Map extends Component {
static propTypes = {
defaultZoom: PropTypes.number,
center: PropTypes.shape({
lat: PropTypes.number,
lng: PropTypes.number
}),
location: PropTypes.shape({
lat: PropTypes.number,
lng: PropTypes.number
}),
onPositionChanged: PropTypes.func
};
static defaultProps = {
defaultZoom: 14,
center: {
lat: 60.1699,
lng: 24.9384
},
location: {},
onPositionChanged: () => {}
};
constructor(props) {
super(props);
this.mapRef = React.createRef((ref) => {
this.mapRef = ref;
});
}
componenDidUpdate() {
console.log(`I'm about to update with props: ${JSON.strongify(prevProps, undefined, 2)}`);
}
onPositionChanged = (location) => {
console.log(`This the new location onPositionChange:${JSON.stringify(location, undefined, 2)}`);
const newLocation = new window.google.maps.LatLng(location.lat, location.lng);
// [NOTE]: try using the panTo() from googleMaps to recenter the map ? but don't know how to call it.
return (
<Marker
position={newLocation}
/>
);
}
render() {
const {
center,
defaultZoom,
location,
onPositionChanged
} = this.props;
return (
<GoogleMap
className="google-map"
onClick={onPositionChanged(location)}
defaultZoom={defaultZoom}
defaultCenter={center}
ref={this.mapRef}
>
{/* <Marker
position={location}
/> */}
{ this.onPositionChanged(location) }
</GoogleMap>
);
}
}
const SchedulerGoogleMap = withScriptjs(withGoogleMap(Map));
const SchedulerMap = props => (
<SchedulerGoogleMap
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${
environment.GOOGLE_MAPS_API_KEY
}&v=3`}
loadingElement={<div style={{ height: '20vh' }} />}
containerElement={<div style={{ height: '100%' }} />}
mapElement={<div style={{ height: '20vh', width: '100%' }} />}
{...props}
/>
);
export { Map, SchedulerMap, SchedulerGoogleMap };
Simply pass the center prop to your GoogleMap component instead of the defaultCenter prop. The center prop is mutable whereas defaultZoom is not.
This is what it seemed to work for me, just in case any other person runs into the same problem.
... ommited_code
class Map extends Component {
... ommited_code
componentDidUpdate(prevProps) {
if (prevProps.location !== this.props.location) {
this.mapRef.panTo(
new window.google.maps.LatLng(this.props.location.lat, this.props.location.lng)
);
}
}
render() {
const {
center,
defaultZoom,
location
} = this.props;
return (
<GoogleMap
className="google-map"
defaultZoom={defaultZoom}
defaultCenter={center}
ref={(ref) => {
this.mapRef = ref;
}}
>
<Marker position={new window.google.maps.LatLng(location.lat, location.lng)} />
</GoogleMap>
);
}
}
...ommited_code
panTo() is a method of the google.maps.Map class. (https://developers.google.com/maps/documentation/javascript/reference/map#Map.panTo)
It seems to be the function you are looking for, so you need to call it on your google map by referencing the className you set for your map, then give the panTo method the LatLang object you created:
window.google.maps.Map(document.getElementsByClassName("google-map")).panTo(newLocation);
i'm using react google maps standalonesearchbox,every thing is ok,but how can i show first near by location in google map search hints(places),generally when we use map with search box then we attach both each other but here i didn't add map.
so here my question is how can i set center or show nearby search first on google places search hints.
here is my code
import React from 'react';
import {connect} from 'react-redux';
import { Input,Icon} from 'antd';
import 'antd/dist/antd.css';
import {pickupHandler,pickupAddHandler,dropoffHandler} from '../actions';
import config from '../../../config'
const { compose, withProps, lifecycle,withHandlers } = require("recompose");
const {
withScriptjs,
} = require("react-google-maps");
const { StandaloneSearchBox } = require("react-google-maps/lib/components/places/StandaloneSearchBox");
const SearchBox = compose(
withProps({
googleMapURL: config.MapApi,
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
}),
lifecycle({
componentWillMount() {
const refs = {}
this.setState({
onSearchBoxMounted: ref => {
refs.searchBox = ref;
},
onBoundsChanged: () => {
this.setState({
bounds: refs.map.getBounds(),
center: refs.map.getCenter(),
})
},
onPlacesChanged: () => {
const places = refs.searchBox.getPlaces();
places.map(({ place_id, formatted_address, geometry: { location } }) =>{
this.props.latlngHandler({lat:location.lat(),lng:location.lng()})
this.props.AddressHandler(formatted_address)
})
this.setState({
places,
});
},
suffix: () =>{
this.props.AddressHandler('')
this.props.latlngHandler(false);
}
})
},
}),
withHandlers(() => {
return{
cutPickIcon:<Icon type="close-circle" />
}
}),
withScriptjs
)(props =>
<div data-standalone-searchbox="">
<StandaloneSearchBox
ref={props.onSearchBoxMounted}
bounds={props.bounds}
onBoundsChanged={props.onBoundsChanged}
onPlacesChanged={props.onPlacesChanged}
>
<Input
prefix={<Icon type="environment-o" style={props.name === 'pick' ? { color: '#EA4335' }: { color: '#00E64D' }} />}
type="text"
placeholder={props.placeHoler}
onChange={props.Field}
onFocus={props.FocusGA}
value={props.Address}
className='input'
suffix={props.Suffix ? <Icon type="close-circle" onClick={props.suffix}/> :''}
/>
</StandaloneSearchBox>
</div>
);
export default connect(null,{pickupAddHandler,pickupHandler,dropoffHandler})(SearchBox)
You can use the maps geocode to set bounds prop on StandaloneSearchBox.
Please refer to my answer on this post.
https://stackoverflow.com/a/53396781/1661712
I am using example in react-google-maps library.
const { compose, withProps, lifecycle } = require("recompose");
const {
withScriptjs,
withGoogleMap,
GoogleMap,
DirectionsRenderer,
} = require("react-google-maps");
const MapWithADirectionsRenderer = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap,
lifecycle({
componentDidMount() {
const DirectionsService = new google.maps.DirectionsService();
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
defaultZoom={7}
defaultCenter={new google.maps.LatLng(41.8507300, -87.6512600)}
>
{props.directions && <DirectionsRenderer directions={props.directions} />}
</GoogleMap>
);
<MapWithADirectionsRenderer />
I want to enable alternative routes in my map. So I used
provideRouteAlternatives: true
so inside callback function
(result, status) => { }
the result have a property routes which is an array of alternative routes.
How can I render those routes into map ? .. I also want to click on routes and they will change the color from active to inactive. When user select the route I need to send on the server property called
overview_polyline
which is inside of routes array, where each route inside the array has this property.
Thank you very much.
If you only want to render those routes on the map, you could use DirectionsRenderer from that library.
https://tomchentw.github.io/react-google-maps/#directionsrenderer
However, this DirectionsRenderer component can not be fully customized like defining the colors or onClick functions. What you could do is creating a customized Directions component using Marker and Polygon which also come from this library. Below is how I made it:
import React, { Component } from 'react';
import { Polyline, Marker } from 'react-google-maps';
import { pinkA200, blue500 } from 'material-ui/styles/colors';
import ntol from 'number-to-letter';
import _ from 'lodash';
const DirectionMarker = ({ data, isEnd, i, onClick }) => {
const { start_location, end_location } = data;
if (isEnd) {
return [
<Marker onClick={onClick} position={start_location} label={ntol(i)} key="end0" />,
<Marker onClick={onClick} position={end_location} label={ntol(i + 1)} key="end1" />
];
}
return <Marker onClick={onClick} position={start_location} label={ntol(i)} />;
};
const Direction = ({ direction, isEnd, i, onClick, isSelected }) => {
const data = direction.routes[0].legs[0];
const path = data.steps.reduce((sum, current) => _.concat(sum, current.path), []);
return [
<DirectionMarker data={data} onClick={onClick} isEnd={isEnd} i={i} key="marker" />,
<Polyline
onClick={onClick}
path={path}
options={{
strokeColor: isSelected ? pinkA200 : blue500,
strokeOpacity: 0.6,
strokeWeight: 6
}}
key="line"
/>
];
};
class Directions extends Component {
constructor(props) {
super(props);
this.state = { selectedSegment: 0 };
}
render() {
const { directions } = this.props;
if (_.isEmpty(directions)) {
return false;
}
return directions.map((d, i) => {
const directionProps = {
direction: d,
i,
key: i,
onClick: () => this.setState({ selectedSegment: i }),
isEnd: i === directions.length - 1,
isSelected: i === this.state.selectedSegment
};
return <Direction {...directionProps} />;
});
}
}
export default Directions;