Reputation: 31
I am trying to make this class component into a functional one that just sends back the longitude and latitude. the class component does give me long/lat but I want to use it as a function. The function should just return the longitude and latitude.
I have tried to make it a function with those functions inside of it but when the call back function getCoords is called in the navigator.getcurrent.... it gives an error saying no assignment.
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
lat: '',
long: ''
};
}
getLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(this.getCoords)
} else {
alert('GeoLocation not enabled');
}
}
getCoords = pos => {
console.log(pos)
this.setState({
lat: pos.coords.latitude,
long: pos.coords.longitude
})
}
render() {
return (
<div>
<button onClick={this.getLocation}>Click me</button>
<p>lat: {this.state.lat}</p>
<p>long {this.state.long}</p>
</div>
);
}
}
export default App;
Do I have to learn react hooks in order to solve my functional component problem?
Upvotes: 2
Views: 667
Reputation: 870
This implements the DRY paradigm a bit more, and I feel like this is a fairly optimal solution.
import React, { useEffect, useState } from 'react';
export function App() {
const [loc, setLoc] = useState({});
const [isLoaded, setIsLoaded = useState(false);
useEffect(() => {
const fetchMap = async () => {
const response = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${loc.lat},${loc.long}&key=${INSERT_API_KEY_HERE}`);
// Do something with the response
setIsLoaded(true);
};
fetchMap();
});
const getLocation = () => {
const { geolocation } = navigator;
if (geolocation) {
geolocation.getCurrentPosition(getCoordinates);
} else {
alert('GeoLocation not enabled');
}
};
const getCoordinates = (pos) => {
const { latitude, longitude } = pos.coords;
setLoc({ lat: latitude, long: longitude });
};
// You can this conditionalize your return statement based
// on the isLoaded state variable. "if (isLoaded)"
return (
<div>
<button onClick={getLocation}>Click me</button>
<p>lat: {loc.lat}</p>
<p>long {loc.long}</p>
</div>
);
};
export default App;
Upvotes: 0
Reputation: 141
The issue is that grabbing coordinates via navigator is an asynchronous request, so the fetch is going out before the coordinates are available. Using the useEffect
hook, you could tell it to fetch the data once the lat and long are updated like so:
const App = () => {
const pos = usePos()
useEffect(() => {
getDataWithCoords()
}, [pos.lat, pos.long])
const getDataWithCoords = () => {
fetch(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${pos.lat},${pos.long}&key=YOUR_API_KEY`)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.log(err))
}
return (
<div>
<p>Lat {pos.lat}</p>
<p>Long: {pos.long}</p>
</div>
)
}
May not be a perfect example, but it works!
Also, make sure you are not posting API keys publicly, you will want to keep those private to your local dev environment. Good luck!
Upvotes: 0
Reputation: 141
Hooks would definitely be the way to go so that you can still maintain the position data in state. Here is the same code but with the useState hook:
const App = () => {
const [pos, setPos] = useState({lat: "", long: ""})
const getLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getCoords)
} else {
alert('GeoLocation not enabled');
}
}
const getCoords = (pos) => {
console.log(pos)
setPos({
lat: pos.coords.latitude,
long: pos.coords.longitude
})
}
return (
<div>
<button onClick={getLocation}>Click me</button>
<p>lat: {pos.lat}</p>
<p>long {pos.long}</p>
</div>
);
}
export default App;
You can see it is not a huge difference, mostly just removing the this
and this.state
keywords and replacing them with pos.lat
and setPos
.
From here if you wanted your component to just return the coords instead of JSX, you would create your own custom hook that would look like this:
const usePos = () => {
const [pos, setPos] = useState({lat: "", long: ""})
const getLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getCoords)
} else {
alert('GeoLocation not enabled');
}
}
const getCoords = (pos) => {
console.log(pos)
setPos({
lat: pos.coords.latitude,
long: pos.coords.longitude
})
}
getLocation()
return { lat: pos.lat, long: pos.long }
}
const App = () => {
const pos = usePos()
return (
<div>
<p>Lat {pos.lat}</p>
<p>Long: {pos.long}</p>
</div>
)
}
Upvotes: 1