I am working on a lifecycle of States. I'm new to React-native and React globally.
I'm trying to display markers from GooglePlacesAPI on the map but my API's URL is invalid. When I log this URL it appears that latitude and longitude are 'null'.
First, I tried to implement the function getCurrentPosition in componentDidMount() where I was setting states "lat" and "lng", and after, my axios's function which use the URL, but my states were null.
So next, I tried to use callback's function. But I get an error : "[Unhandled promise rejection: TypeError: Cannot read property 'setState' of undefined]"
Here's my code :
import * as React from 'react';
import { StyleSheet } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
import MapView from 'react-native-maps';
import axios from 'axios';
var API_KEY= '###################';
var GOOGLE_PLACES_URL = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json';
class MapScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
isloading: null,
lat: null,
lng: null,
error:null,
markers: [],
};
}
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
console.log(position);
this.setState({
lat: position.coords.latitude,
lng: position.coords.longitude,
error: null,
}, () => {
getMarkers(this.state.lat, this.state.lng)
});
},(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: false, timeout: 200000, maximumAge: 1000 },
);
// My first try was to put the axios.get(url) here.
}
function getMarkers(lat, lng){
const url =
`${GOOGLE_PLACES_URL}?location=${lat},${lng}&radius=1500&keyword=grow+shop&key=${API_KEY}`;
axios.get(url)
.then(res =>
res.data.results.map(marker => ({
latitude: `${marker.geometry.location.latitude}`,
longitude: `${marker.geometry.location.longitude}`,
name: `${marker.name}`,
isOpen: `${marker.opening_hours.open_now}`,
adress: `${marker.vicinity}`
})))
.then(markers => {
console.log(url)
console.log(markers)
this.setState({
markers,
isloading: false
})
})
.catch(error => this.setState({error, isloading: true}));
}
render() {
const { markers, lat, lng } = this.state
return (
this.state.lat !== null && <MapView style={styles.map} initialRegion={{
latitude:this.state.lat,
longitude:this.state.lng,
latitudeDelta: 1,
longitudeDelta: 1,
}}
showsUserLocation= {true}>
{markers.map(marker => {
return (<MapView.Marker
coordinate = {{
latitude:this.state.lat,
longitude:this.state.lng
}}/>)
})}
</MapView>
)}
}
export default MapScreen;
When I log 'Position' in 'getCurrentPosition' :
Object {
"coords": Object {
"accuracy": 65,
"altitude": 11.887725830078125,
"altitudeAccuracy": 10,
"heading": -1,
"latitude": 44.83189806318307,
"longitude": -0.5747879551813496,
"speed": -1,
},
"timestamp": 1589450273414.4202,
}
The map is working because the Initial Region is center on my location.
Maybe should I create file 'utils/getCurrentPosition' where I could use React Context to set latitude and longitude's user ?
I heard that getCurrentPosition was 'async' and I think it's for this reason that my first try was a failure.
EDIT : Finally I retrieve expected results from the APi so my callback function is working, I just need to figure out how to fill my state 'markers' with the data. I will post my code when everything working fine.
So everything is working fine now.
The callback function is perfect for this kind of problem.
Here is my code to solve it :
class MapScreen extends React.Component {
constructor(props) {
super(props);
this.getMarkers = this.getMarkers.bind(this);
this.state = {
isloading: true,
lat: null,
lng: null,
error:null,
markers: [],
};
}
getMarkers(lat, lng){
const url = `${GOOGLE_PLACES_URL}?location=${lat},${lng}&radius=1500&keyword=grow+shop&key=${API_KEY}`;
fetch(url)
.then(res => res.json())
.then((data) => {
this.setState({ markers: data.results });
})
.catch(error => this.setState({error, isloading: true}));
}
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
console.log(position);
this.setState({
lat: position.coords.latitude,
lng: position.coords.longitude,
error: null }, () => {
this.getMarkers(this.state.lat, this.state.lng);
});
},(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 200, maximumAge: 1000 },
);
}
render() {
const { markers } = this.state
return (
this.state.lat !== null && <MapView style={styles.map} initialRegion={{
latitude:this.state.lat,
longitude:this.state.lng,
latitudeDelta: 1,
longitudeDelta: 1,
}}
showsUserLocation= {true}
>
{this.state.markers !== null && this.state.markers.map(marker => (
<MapView.Marker
coordinate = {{
latitude:marker.geometry.location.lat,
longitude:marker.geometry.location.lng
}}>
</MapView.Marker>
))}
</MapView>
)}
}
I was not handling the JSON's response well.
Now I do. I just have to attribute 'Key prop' to each prop and it's good.