I'm trying to get the user's location (that works) and set it to the current state in a React component (this part doesn't). I've looked through a few answers on here and can't tell what I'm doing wrong.
Here's what I have:
class Container extends Component {
constructor() {
super()
this.state = {
location: {
lat: 0,
lng: 0
}
}
}
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
let lat = position.coords.latitude
let lng = position.coords.longitude
console.log("getCurrentPosition Success " + lat + lng) // logs position correctly
this.setState({
location: {
lat: lat,
lng: lng
}
})
},
(error) => {
this.props.displayError("Error dectecting your location");
console.error(JSON.stringify(error))
},
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
)
}
render() {
const location = this.state.location
return (
<div>
<Map center={location}/>
</div>
)
}
}
It looks similar to what other people have, and I've tried a few different ways, but I can't get the state to set. Is there something I'm missing or doing wrong?
The setState command is working fine.
Note that the get location is an async. call, and therefore the render() will be called twice. The first time it call, the lat/lng is zero.
You can add a logic to check it is zero and return null, if you want to render the output after getting the lat/lng from the geolocation services.
Related
When I allow browser to get the Geolocation upon button Click, I am able to see the Latitude and Longitude. But when I block the site for accessing location, I am getting "Unable to retrieve your location" and Latitude and Longitude as well ... Here When I Block the site, I should get only message "Unable to retrieve your location" and Latitude and Longitude should not show...Please find the Screenshot as well
Here is my Code
const GeolocationButton = () => {
const [lat, setLat] = useState(null);
const [lng, setLng] = useState(null);
const [status, setStatus] = useState(null);
const getLocation = () => {
if (!navigator.geolocation) {
setStatus('Geolocation is not supported by your browser');
} else {
setStatus('Please allow brower to access your Location');
navigator.geolocation.getCurrentPosition((position) => {
setStatus(null);
setLat(position.coords.latitude);
setLng(position.coords.longitude);
}, () => {
setStatus('Unable to retrieve your location');
});
}
}
return (
<div className="App">
<button onClick={getLocation}>Get Location</button>
<h1>Coordinates</h1>
<p>{status}</p>
{lat && <p>Latitude: {lat}</p>}
{lng && <p>Longitude: {lng}</p>}
</div>
);
}
export default GeolocationButton
lat and lng are state variables, and state is, well, persistent. Consequently, when you set lat and lng, they retain those values, even if you later block access to location data.
There are various ways to resolve:
Since status, lat and lng are all interdependent, use a single state variable to store all three. This approach best realizes the dependent relationship between the variables.
const GeolocationButton = () => {
// could also initialize location to `{}`
const [location, setLocation] = useState({status:null,lat:null,lng:null});
const getLocation = () => {
if (! navigator.geolocation) {
// don't spread previous state into new state, and
// no need to explicitly set location.lat & .lng
setLocation({
status: 'Geolocation is not supported by your browser',
});
} else {
…
When setting status, also set lng and lat. This doesn't explicitly implement the interdependency between variables, and so requires more discipline on the part of the programmer.
if (! navigator.geolocation) {
setStatus('Geolocation is not supported by your browser');
setLat(null);
setLng(null);
} else {
// note: there's a typo in "browser" in the question sample
setStatus('Please allow browser to access your Location');
setLat(null);
setLng(null);
…
When getting the location, initialize lat and lng to null:
const getLocation = () => {
setLat(null);
setLng(null);
When displaying lat and lng, check that status isn't set (you should also check status before displaying it):
{ status ? <p>{status}</p>
{!status && lat && <p>Latitude: {lat}</p>}
or:
{ status
? <p>{status}</p>
: <>
{lat && <p>Latitude: {lat}</p>}
{lng && <p>Longitude: {lng}</p>}
</>
}
Sorry I am a newbie in React and working on useEffect function. Getting above error "Maximum Update Depth Exceeded".
Problem Statement: I need to hide the icon based on visibility value. I have an object Location History which has multiple locations. I am binding locations on map based on coordinates and within circle showing all the locations. But I am not able to hide this within same circle radius.
Here is my code:
export const performLocationHistorySearch = () => async (dispatch) => {
consolehelper("====================================");
consolehelper("Executing History Search");
let locationdata= store.getState().global.locationhistory;
console.log("location history", locationdata);
const center: Location = {
lat: store.getState().global.searchLat,
lng: store.getState().global.searchLng,
};
consolehelper(center);
const radius = store.getState().global.searchRad;
if (locationdata !== null) {
console.log(locationdata);
let _locations =locationdata.locations.map((el) => {
const crowDistance = calculateCrowDistance(
{ lat1: parseFloat(el.latitude), lon1: parseFloat(el.longitude) },
{ lat2: center.lat, lon2: center.lng }
);
console.log(crowDistance);
consolehelper("====================================");
return {
...el,
_isVisible_:
radius >= crowDistance ,
__distance: crowDistance,
};
});
console.log(_locations.filter((el) => el._isVisible_));
dispatch(globalSlice.actions.setlocationRecords({
...locationdata,
locations:_locations
}));
}
};
Second piece of code calling locations, here it is:
useEffect(() => {
console.log("====use effect location history====");
if (locationhistory && searchRad && searchLat && searchLng) {
dispatch(performLocationHistorySearch());
console.log("====use effect location history====");
}
}, [
dispatch,
locationhistory,
searchLat,
searchLng,
searchRad,
]);
While calling above function getting Error "maximum update depth exceeded". Any help would be appreciated.
Thanks
Making my first react app. I want to update the google maps api based on the user's location.
I am receiving the error "this is undefined". I understand using .bind(this) and wrapping in an arrow function but think this case is a bit different because I am setting state inside a nested function:
constructor(props) {
super(props);
this.state = {zip: null, lat: 40.5304 , lng: -100.6534 , zoom: 3.8 };
this.updateCurrentPosition= this.updateCurrentPosition.bind(this);
}
//...
updateCurrentPosition = () => {
navigator.geolocation.getCurrentPosition(success, error);
function success(pos) {
this.setState(`{lat: ${pos.coords.latitude}, lng: ${pos.coords.longitude}, zoom: ${3.8}`)
}
function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
};
}
ops = () => {
return {
center: { lat: this.state.lat, lng: this.state.lng },
zoom: this.state.zoom
}
};
Arrow functions automatically bind functions to the parent class. If a function is not binded, or not an arrow function, "this" will refer only to the function itself, even if it is nested. Your success function (and failure function too) is not bound to the parent class, as you have neither binded it or defined it as an arrow function.
The problem is that this is undefined under strict mode in Javascript. You can refer to this paragraph to read more http://2ality.com/2014/05/this.html
For your particular question, when you defined success and error, the two functions are not bound to parents.
The following modification by defining the functions as arrow functions will resolve your issue.
const success = (pos) => {
this.setState(`{lat: ${pos.coords.latitude}, lng: ${pos.coords.longitude}, zoom: ${3.8}`)
}
const error = (err) => {
console.warn(`ERROR(${err.code}): ${err.message}`);
};
So, I've instead passed the functions directly as arguments to the getCurrentPosition method and it seems to work fine.
updateCurrentPosition = () => {
navigator.geolocation.getCurrentPosition( (pos) => {
this.setState({ lat: pos.coords.latitude, lng: pos.coords.longitude, zoom: 1 })
},
(err) => {
console.warn(`ERROR(${err.code}): ${err.message}`)
}
)
}
I can’t access the values lat , lng from data() in maps() method.
my vue.js component
code link : https://gist.github.com/melvin2016/c8082e27b9c50964dcc742ecff853080
console image of lat,lng
enter image description here
<script>
import Vue from 'vue';
import navbarSec from './navbarSec.vue';
export default {
data(){
return{
lat: '',
lng: '',
mapState: window.mapState,
from:'',
to:'',
placesFrom:[],
placesTo:[]
};
},
components:{
'navbar':navbarSec
},
created(){
var token = this.$auth.getToken();
this.$http.post('http://localhost:3000/book',{},{headers: {'auth':token}}).then(function(data){
this.session = true;
})
.catch(function(data){
this.session = false;
this.$auth.destroyToken();
Materialize.toast(data.body.message, 6000,'rounded');
this.$router.push('/login');
});
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition((data)=>{
this.lat = data.coords.latitude;
this.lng = data.coords.longitude;
this.from=data.coords.latitude+' , '+data.coords.longitude;
});
}else{
Materialize.toast("Cannot Get Your Current Location !", 6000,'rounded');
}
},
mounted(){
if (this.mapState.initMap) {// map is already ready
var val = this.mapState.initMap;
console.log(val);
this.maps();
}
},
watch: {
// we watch the state for changes in case the map was not ready when this
// component is first rendered
// the watch will trigger when `initMap` will turn from `false` to `true`
'mapState.initMap'(value){
if(value){
this.maps();
}
},
from : function(val){
if(val){
var autoComplete = new google.maps.places.AutocompleteService();
autoComplete.getPlacePredictions({input:this.from},data=>{
this.placesFrom=data;
});
}
},
to:function(val){
if(val){
var autoComplete = new google.maps.places.AutocompleteService();
autoComplete.getPlacePredictions({input:this.to},data=>{
this.placesTo=data;
});
}
}
},
methods:{
maps(){
var vm = this;
var lati = vm.lat;
var lngi = vm.lng;
console.log(lati+' '+lngi);
var map;
var latlng = {lat: lati, lng:lngi };
console.log(latlng);
this.$nextTick(function(){
console.log('tickkkk');
map = new google.maps.Map(document.getElementById('maplo'), {
zoom: 15,
center: latlng
});
var marker = new google.maps.Marker({
position: latlng,
map: map
});
});
}
}
}
</script>
This is happening because you're calling maps() in the mounted at which point, the navigator.geolocation.getCurrentPosition((data) => {}) code hasn't resolved. With that in mind, call this.maps() within the getCurrentPosition method i.e:
navigator.geolocation.getCurrentPosition((data)=>{
this.lat = data.coords.latitude;
this.lng = data.coords.longitude;
this.from=data.coords.latitude+' , '+data.coords.longitude;
this.maps()
});
I've not looked in detail but you might be able to change the bits within the maps() method to remove the nextTick stuff when you do this as you'll be calling it a lot later in the cycle at which point everything will have been rendered.
I'm trying to display geolocation variables position.coords.lat/long and I'm having trouble storing the values in a global scope. Here is the code:
var GeoLoco = React.createClass({
lat: 0,
long: 0,
handler: function(position) {
this.lat = position.coords.latitude;
this.long = position.coords.longitude;
console.log("Lat,Long: "+this.lat+","+this.long);
},
render: function() {
navigator.geolocation.getCurrentPosition(this.handler);
return <p>Lat,Long: {this.lat},{this.long}</p>;
}
});
console.log displays the location data, but this.lat and this.long render as 0
Even if your variable's values changed, you have to re-render your component to update what you're seeing.
The component's state does it for you.
More information here
By default, when your component's state or props change, your component will re-render.
So :
var GeoLoco = React.createClass({
getInitialState: function() {
return {lat: 0, long: 0};
},
handler: function(position) {
this.setState({
lat: position.coords.latitude,
long: position.coords.longitude
});
},
render: function() {
// If this.state.lat is not equal to 0, do not call again getCurrentPosition()
if (!this.state.lat)
navigator.geolocation.getCurrentPosition(this.handler);
return <p>Lat,Long: {this.state.lat},{this.state.long}</p>;
}
});
If you don't want to use state, you can call forceUpdate() at the end of your handler method.
handler: function(position) {
this.lat = position.coords.latitude;
this.long = position.coords.longitude;
console.log("Lat,Long: "+this.lat+","+this.long);
this.forceUpdate();
},