let lon, lat;
let weather;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
lat = position.coords.latitude;
lon = position.coords.longitude;
console.log(typeof lat)
});
}
class Button extends React.Component{
state = {latt: lat}
render(){
return(
<div>
{this.state.latt}
<h1>ss</h1>
</div>
)}}
class Appp extends React.Component {
render(){
return(
<Button />
)}
}
ReactDOM.render(<Appp />, mountNode)
what i did
When I console.log the variable I get a number but why cant I use it as a value in state. Even putting it inside an array makes no difference.
it should be this:
let lat, lon, weather;
class Calendar extends React.Component {
constructor(props){
super(props);
this.state = {
lat: null,
lon: null
}
this.updateLatLon = this.updateLatLon.bind(this);
}
updateLatLon(){
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
this.setState(() => {
return {lat: position.coords.latitude, lon: position.coords.longitude}
});
});
}
}
componentWillMount(){
this.updateLatLon();
}
render(){
return (
<div>
{this.state.lat}
</div>
)
}
}
You change the state by using setState()
navigator.geolocation.getCurrentPosition(function(position) {
this.setState({
lat: position.coords.latitude,
lon: position.coords.longitude
});
console.log(typeof lat)
});
Related
What I'm trying to do is send in an array of addresses to a component, use google's geocoder to convert those addresses into lat / long coordinates, and then plat those places on a google map with markers using the google maps api react wrapper. I followed this tutorial pretty closely (https://dev.to/jessicabetts/how-to-use-google-maps-api-and-react-js-26c2) with the biggest difference being that I worked in geocoder. Because geocoder is asynchronous, I can't get the map to re-render with the newly converted coordinates after the promise is resolved. Below is the code I have right now:
import React, { Component } from 'react';
import {Map, InfoWindow, Marker, GoogleApiWrapper} from 'google-maps-react';
const mapStyles = {
width: '100%',
height: '300px'
};
let geocoder;
let addressData = [{location: "146 Pierrepont St, Brooklyn, NY, USA"}, {location: "153 Remsen St, Brooklyn, NY, USA"}];
export class MapContainer extends Component {
constructor (props) {
super(props);
this.onMarkerClick = this.onMarkerClick.bind(this);
this.displayMarkers = this.displayMarkers.bind(this);
this.state = {
lat: 40.6946768,
lng: -73.99161700000002,
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {},
places: [],
stores: [{latitude: 47.49855629475769, longitude: -122.14184416996333},
{latitude: 47.359423, longitude: -122.021071},
{latitude: 47.2052192687988, longitude: -121.988426208496},
{latitude: 47.6307081, longitude: -122.1434325},
{latitude: 47.3084488, longitude: -122.2140121},
{latitude: 47.5524695, longitude: -122.0425407}]
}
}
componentDidMount () {
this.plotPoints()
}
plotPoints () {
let locations = this.getPoints(geocoder)
let places = new Array()
Promise.all(locations)
.then(function(returnVals) {
returnVals.forEach(function(latLng) {
let place = {latitude: latLng[0], longitude: latLng[1]}
places.push(place)
})
})
this.setState (() => {
return {
places: places
}
});
}
getPoints(geocoder) {
let locationData = [];
for (let i = 0; i < addressData.length; i++) {
locationData.push(this.findLatLang(addressData[i].location, geocoder))
}
return locationData // array of promises
}
findLatLang(address, geocoder) {
return new Promise(function(resolve, reject) {
geocoder.geocode({
'address': address
}, function(results, status) {
if (status === 'OK') {
console.log(results);
resolve([results[0].geometry.location.lat(), results[0].geometry.location.lng()]);
} else {
reject(new Error('Couldnt\'t find the location ' + address));
}
})
})
}
displayMarkers (stores) {
return stores.map((place, index) => {
return <Marker key={index} id={index} position={{
lat: place.latitude,
lng: place.longitude
}}
onClick={() => console.log("You clicked me!")} />
})
}
onMarkerClick (props, marker, e) {
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
});
};
render() {
geocoder = new this.props.google.maps.Geocoder();
return (
<div className="container place-map">
<div className="row">
<div className="col-md-12">
<Map
google={this.props.google}
zoom={14}
style={mapStyles}
initialCenter={{
lat: this.state.lat,
lng: this.state.lng
}}
>
{this.displayMarkers(this.state.stores)}
{this.displayMarkers(this.state.places)}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
>
<div>Your Location Here!</div>
</InfoWindow>
</Map>
</div>
</div>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: 'AIzaSyCOJDrZ_DXmHzbzSXv74mULU3aMu3rNrQc'
})(MapContainer);
The array of "stores" renders markers on the map since there are coordinates available at the initial render of the map - but the coordinates that get pushed onto the "places" array never render. If I put a log statement of the "places" into render() I can see that I am getting back valid coordinates from geocoder.
Help! Been banging my head on this for forever (as you can tell by the current sloppy state of the code).
You need to move the setState for places into the Promise.all callback.
You are calling it when the array is still empty and before the promises have resolved
Promise.all(locations)
.then((returnVals) =>{
returnVals.forEach((latLng) => {
let place = {
latitude: latLng[0],
longitude: latLng[1]
}
places.push(place)
})
// places now populated
this.setState(() => {
return {
places: places
}
});
});
I am learning react, and is trying to plot a map with mapbox. I am stuck with how to render elements seperatly.
In the render part, there is a <div/> element and a component <CityWeather/> wrapped. div is a reference to map. The <Cityweather /> is an info box which is supposed to display weather information based on lat and long. The app.js file render method is
render(){
console.log(this.state);
return(
<section>
<div className="map-container" ref={x => { this.mapContainer = x;}}/>
<CityWeather lat={this.state.lat} lng={this.state.lng} />
</section>
);
The componentDidMount() is
componentDidMount() {
this.getLocation();
mapboxgl.accessToken = "";
const { lng, lat, zoom } = this.state;
const map = new mapboxgl.Map({
container: this.mapContainer,
style: "mapbox://styles/mapbox/streets-v11",
center: [lng, lat],
zoom: zoom
});
map.on("moveend", () => {
const { lng, lat } = map.getCenter();
this.setState({
lng: lng.toFixed(4),
lat: lat.toFixed(4),
zoom: map.getZoom().toFixed(2)
});
});
}
The <CityWeather /> component
class CityWeather extends Component {
constructor(props) {
super(props);
this.state = {
name: ""
};
}
componentDidMount() {
console.log(this.props); // this logs only 1 time when the page loads
fetch("api?lat=" + this.props.lat +"&lon=" +this.props.lng + "&appid=")
.then(res => res.json())
.then(data => {this.setState({ name: data.name });
}); // get name from lat and long and store it in state
}
render() {
return (
<div className="city-weather">
<p>
City | <span className="city">
{this.state.name}</span>
</p>
</div>
);
}
}
On each event the console is logging the updated latitude, longitude and zoom. Also the <CityWeather/> is also rendered for Ist time. After that the component is not rendered on state change.
You have loaded weather data in componentDidMount. It will only run the first time that the component is rendered, Not on every state change.
This is the correct code:
class CityWeather extends Component {
constructor(props) {
super(props);
this.state = {
name: ""
};
}
componentDidMount() {
this.load();
}
load(){
console.log(this.props); // this logs only 1 time when the page loads
fetch("api?lat=" + this.props.lat + "&lon=" + this.props.lng + "&appid=")
.then(res => res.json())
.then(data => {
this.setState({ name: data.name });
}); // get name from lat and long and store it in state
}
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.lat !== prevProps.lat || this.props.lng !== prevProps.lng) {
this.load();
}
}
render() {
return (
<div className="city-weather">
<p>
City | <span className="city">
{this.state.name}</span>
</p>
</div>
);
}
}
Did you add a log in the listener? I think the method was not called because you did not move. you can use timer and some mock data to test the render.
I want to make two components: App and Map. However when I try to make a new brand Map component and send the data from App to Map component, I cannot.
My App (default) component holds the data as a state. When I try to send this state to the Map component. It holds the data as a prop.
And of course If I don't separate them and write everything in App.js, everything works as I expected (markers shown on the map). But I want to control all states in the parent component.
Am I violating a fundamental React rule? How can I fix that?
App.js
import React, { Component } from "react";
import "./App.css";
import Map from "./Map";
class App extends Component {
constructor(props) {
super(props);
this.state = {
locations: [],
markers: []
};
}
componentDidMount() {
fetch(
"correct_foursquare_api_url"
)
.then(response => response.json())
.then(data =>
data.response.venues.map(place => ({
id: place.id,
name: place.name,
lat: place.location.lat,
lng: place.location.lng
}))
)
.then(locations => {
this.setState({ locations });
});
}
render() {
return (
<div className="App">
<Map locations={this.state.locations} />
</div>
)
}
}
export default App;
Map.js
import React, { Component } from "react";
/* global google */
class Map extends Component {
constructor(props) {
super(props);
this.state = {
locations: [],
markers: []
};
}
componentDidMount() {
this.callMap();
}
callMap() {
window.initMap = this.initMap;
loadJS(
"api_url"
);
}
// Map
initMap = () => {
const { locations, markers } = this.state;
let map = new google.maps.Map(document.getElementById("map"), {
center: { lat: 59.4827293, lng: -83.1405355 },
zoom: 13
});
// Markers
for (var i = 0; i < locations.length; i++) {
var title = locations[i].name;
var position = new google.maps.LatLng(locations[i].lat, locations[i].lng);
var id = locations[i].id;
var marker = new google.maps.Marker({
map: map,
position: position,
title: title,
animation: google.maps.Animation.DROP,
id: id
});
markers.push(marker);
}
};
render() {
return <div id="map" />;
}
}
function loadJS(src) {
var ref = window.document.getElementsByTagName("script")[0];
var script = window.document.createElement("script");
script.src = src;
script.async = true;
ref.parentNode.insertBefore(script, ref);
}
export default Map;
You store your locations in the state of the App component, but you also have locations in state of the Map component that you use on mount.
You could instead wait with rendering the Map component until the locations request is finished, and then use the locations props in the Map component passed down from App instead.
Example
class App extends Component {
constructor(props) {
super(props);
this.state = {
locations: [],
markers: []
};
}
componentDidMount() {
fetch("correct_foursquare_api_url")
.then(response => response.json())
.then(data => {
const locations = data.response.venues.map(place => ({
id: place.id,
name: place.name,
lat: place.location.lat,
lng: place.location.lng
}));
this.setState({ locations });
});
}
render() {
const { locations, markers } = this.state;
if (locations.length === 0) {
return null;
}
return (
<div className="App">
<Map locations={locations} markers={markers} />
</div>
);
}
}
class Map extends Component {
// ...
initMap = () => {
const { locations, markers } = this.props;
// ...
};
// ...
}
I'm new to React and currently trying to learn how to use react-google-maps library. Tried to show a map with users geolocation as the initialCenter of the map.
This is my code:
import React from "react";
import { GoogleApiWrapper, Map } from "google-maps-react";
export class MapContainer extends React.Component {
constructor(props) {
super(props);
this.state = { userLocation: { lat: 32, lng: 32 } };
}
componentWillMount(props) {
this.setState({
userLocation: navigator.geolocation.getCurrentPosition(
this.renderPosition
)
});
}
renderPosition(position) {
return { lat: position.coords.latitude, lng: position.coords.longitude };
}
render() {
return (
<Map
google={this.props.google}
initialCenter={this.state.userLocation}
zoom={10}
/>
);
}
}
export default GoogleApiWrapper({
apiKey: "-----------"
})(MapContainer);
Insted of creating a map with users location I get an initialCenter of my default state values.
How can I fix it? Am I even using the lifecycle function right?
Thank you very much for your help
navigator.geolocation.getCurrentPosition is asynchronous, so you need to use the success callback and set the user location in there.
You could add an additional piece of state named e.g. loading, and only render when the user's geolocation is known.
Example
export class MapContainer extends React.Component {
state = { userLocation: { lat: 32, lng: 32 }, loading: true };
componentDidMount(props) {
navigator.geolocation.getCurrentPosition(
position => {
const { latitude, longitude } = position.coords;
this.setState({
userLocation: { lat: latitude, lng: longitude },
loading: false
});
},
() => {
this.setState({ loading: false });
}
);
}
render() {
const { loading, userLocation } = this.state;
const { google } = this.props;
if (loading) {
return null;
}
return <Map google={google} initialCenter={userLocation} zoom={10} />;
}
}
export default GoogleApiWrapper({
apiKey: "-----------"
})(MapContainer);
Beginner here. I have a button that gets latitude and longitude using the geolocation API. I get the location fine on my console, but I'm having trouble showing them in a input box (so that I can then post the location information later). Below is my code for the component:
export class GetLocation extends Component{
constructor(){
super();
this.state = {
latitude: '',
longitude: ''
};
this.getMyLocation = this.getMyLocation.bind(this);
}
ComponentDidMount(){
this.getMyLocation();
}
getMyLocation = (e) => {
let location = null;
let latitude = null;
let longitude = null;
if (window.navigator && window.navigator.geolocation) {
location = window.navigator.geolocation
}
if (location){
location.getCurrentPosition(function (position) {
latitude = position.coords.latitude;
longitude= position.coords.longitude;
console.log(latitude);
console.log(longitude);
})
}
this.setState({latitude: latitude, longitude: longitude})
}
render(){
return(
<div>
<p>Your location is </p>
<Field name="latitude" component="input" onChange={this.getMyLocation}/>
<button type="button" onClick={this.getMyLocation}>Get Geolocation</button>
</div>
);
}
}
I'm using redux-form and this component is a part of a wizard form (in case you were wondering about the Field Component)
ComponentDidMount should be componentDidMount. I believe you have to set a value prop to your Field right?
Also, as #bennygenel mentioned, you don't need to bind getMyLocation in the constructor since you are already using arrow function (I did on my example, feel free to change it). In order to have access to this.state inside getCurrentPosition's callback, you either need to bind the success callback or make use of arrow function.
class App extends React.Component {
constructor() {
super()
this.state = {
latitude: '',
longitude: '',
}
this.getMyLocation = this.getMyLocation.bind(this)
}
componentDidMount() {
this.getMyLocation()
}
getMyLocation() {
const location = window.navigator && window.navigator.geolocation
if (location) {
location.getCurrentPosition((position) => {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
})
}, (error) => {
this.setState({ latitude: 'err-latitude', longitude: 'err-longitude' })
})
}
}
render() {
const { latitude, longitude } = this.state
return (
<div>
<input type="text" value={latitude} />
<input type="text" value={longitude} />
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Like the other answers say you need to pass longitude and latitude values to the input so you can be able to show but there is another problem. You are not setting the longitude and latitude in the right place.
if (location){
location.getCurrentPosition(function (position) {
latitude = position.coords.latitude;
longitude= position.coords.longitude;
console.log(latitude);
console.log(longitude);
this.setState({
latitude: latitude,
longitude: longitude
}); // you should set state when you have the values.
}.bind(this)); // you need to bind this so you can use setState
}