I feel I've tried every combination of onPress events and function calls but nothing works. I am too noob to see what the issue is. Is it because it's rested in a few return statements?
I've ellipse'd code that isn't relevant. It works fine but the button will appear to not do anything. No errors or anything.
Thanks
import React from 'react';
import {
...
Button,
} from 'react-native';
//Import other react maps stuff
......
const dest = {latitude: -37.836037, longitude: 145.036730};
const waypoint = [
{address: '123 Fake St, Anglesea', latitude: -37.861738, longitude: 145.002500},
{address: '321 Real St, Anglesea', latitude: -37.806694, longitude: 145.010026}
];
class TodaysJobs extends React.Component {
state = {
location: null,
errorMessage: null,
};
//Get user current location
componentWillMount() {
....
}
_getLocationAsync = async () => {
....
};
moveMap() {
alert('Simple Button pressed');
const coordinate = waypoint[0];
this.map.animateToRegion({
latitude: -37.223423,
longitude: 145.423442,
latitudeDelta: 0.1,
longitudeDelta: 0.1
},
350
);
}
render() {
if (this.state.loaded) {
// if we have an error message show it
if (this.state.errorMessage) {
return (
....
);
} else if (this.state.location) {
// if we have a location show it
return (
<View style={{ flex: 1 }}>
<MapView
ref={(ref) => { this.mapRef = ref }}
style={ styles.mapStyle }
region={{
latitude: this.state.location.coords.latitude,
longitude: this.state.location.coords.longitude,
latitudeDelta: 0.1,
longitudeDelta: 0.1
}}
>
{waypoint.map(function(item, i){
return <MapView.Marker
key={i}
coordinate={item}
/>
})}
<MapViewDirections
origin={this.state.location.coords}
waypoints={waypoint}
destination={dest}
/>
</MapView>
<ScrollView style={ styles.mapStyle }>
{waypoint.map(function(item, i){
return (
<View key={i} style={ styles.houseList }>
<Text>{item.address}</Text>
<Button
title={item.address}
onPress={this.moveMap}
/>
</View>
);
})}
</ScrollView >
</View>
);
}
} else {
// if we haven't loaded show a waiting placeholder
return (
<View>
<Text>Waiting...</Text>
</View>
);
}
}
}
export default TodaysJobs;
//Styles
....
You are using waypoint.map(function(item, i) and then onPress={this.moveMap}. this is defined in runtime and so this.moveMap will be undefined.
Try using fat arrow function instead of native function.
{
waypoint.map((item, i) => {
return (
<View key={i} style={styles.houseList}>
<Text>{item.address}</Text>
<Button
title={item.address}
onPress={this.moveMap}
/>
</View>
);
})
}
if you want to read more about the difference read this blog
Related
I'm new to React and React native and am trying to retrieve data from an API and then render it but I seem to be running into problems.
I'm getting errors like:
undefined is not an object (evaluating 'attractions.map') in RenderPhotos_render
I may have jumped into React Native too early...So excuse my lack of knowledge!
import React, {Component} from 'react';
import {StyleSheet, View, ActivityIndicator} from 'react-native';
import MapView, {Marker} from 'react-native-maps';
import {connect} from 'react-redux';
const mapStateToProps = state => {
return {
attractions: state.attractions.attractions,
};
};
const mapDispatchToProps = dispatch => {
return {
GET_Attractions(callback) {
dispatch({type: 'attractions/GET_Attractions', callback});
},
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(
class Home extends Component {
state = {
loading: true,
};
componentDidMount = () => {
const callback = () => {
this.setState({
loading: false,
});
};
this.props.GET_Attractions(callback);
};
renderMapMarker = () => {
const {attractions} = this.props;
return attractions.map(marker => {
return (
<Marker
key={marker.caseId}
title={marker.caseName}
description="點擊查看詳細資料"
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}
/>
);
});
};
render() {
if (this.state.loading) {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
} else {
return (
<View style={styles.container}>
<MapView
style={styles.mapView}
initialRegion={{
latitude: 24.149706,
longitude: 120.683813,
latitudeDelta: 8,
longitudeDelta: 8,
}}>
{this.renderMapMarker()}
</MapView>
</View>
);
}
}
},
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
mapView: {
width: '100%',
height: '100%',
},
});
By default attractions might be undefined so you can check to validate first then render if it has data to render like
render() {
if (this.state.loading) {
return (
...
);
} else {
return (
<View style={styles.container}>
<MapView
...
>
{this.props.attractions && this.renderMapMarker()} // and this
</MapView>
</View>
);
}
}
You are trying to use a prop "attractions" that is being populated from the reducer, so initially when your screen is being rendered the prop "attractions" will be undefined so you need to achieve this with the condition to make the error go away.
{attractions && this.renderMapMarker()}
Just add ? after attractions and it should work.
renderMapMarker = () => {
const {attractions} = this.props;
return attractions?.map(marker => {
return (
<Marker
key={marker.caseId}
title={marker.caseName}
description="點擊查看詳細資料"
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}
/>
);
});
};
I have implemented this example where I can zoom in to the given coordinates by clicking on the button.
Below you can read what I aiming to implement and I couldn't:
First, I want to be able to read coordinates out of a dynamic array, I tried by putting the array in the state but it fails.
const ASPECT_RATIO = width / height;
const LATITUDE = 37.78825;
const LONGITUDE = -122.4324;
const LATITUDE_DELTA = 0.0922;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
const MARKERS = [
{
latitude: 42.637368,
longitude: 21.148682,
},
{
latitude: 42.604021,
longitude: 21.261292,
},
{
latitude: 42.500833,
longitude: 21.181641,
}
];
const DEFAULT_PADDING = { top: 60, right: 60, bottom: 60, left: 60 };
export default class map_of_patients extends React.Component {
constructor(){
this.state={}
}
fitAllMarkers() {
this.map.fitToCoordinates(MARKERS, {
edgePadding: DEFAULT_PADDING,
animated: true,
});
}
render() {
return (
<View style={styles.container}>
<MapView
ref={ref => {
this.map = ref;
}}
style={styles.map}
initialRegion={{
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
}}
>
{MARKERS.map((marker, i) => (
<Marker key={i} identifier={`id${i}`} coordinate={marker} />
))}
</MapView>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={() => this.fitAllMarkers()}
style={[styles.bubble, styles.button]}
>
<Text>Fit All Markers</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
Second I would like to call the function fitAllMarkers into coordinates on start, so I don't have to click somewhere to do it. I tried by calling in inside componentDidMount() but didn't work either.
Third, I would like to zoom in to the region by giving the coordinates from the dynamic array.
I managed to fix all the issues mentioned in the question by doing the following:
-To fit all markers on initialization of the map I did as #Marek Lisik suggested using onMapReady={this.fitAllMarkers.bind(this)}.
-And to read from a dynamic array I managed to pass the array beforehand to the state and by the time the map is initialized it already had some data.
Here is the entire code again with the changes:
constructor(props) {
super(props);
this.state = {
region: {
latitude: 42.65847,
longitude: 21.16070,
latitudeDelta: 0.500,
longitudeDelta: 0.500 * width / height,
},
MARKERS: [
{
latitude: 42.637368,
longitude: 21.148682,
description: "dfsdf",
title: "title"
},
{
latitude: 42.604021,
longitude: 21.261292,
description: "sdfsdf",
title: "title"
},
{
latitude: 42.500833,
longitude: 21.181641,
description: "sdfsdfds",
title: "title"
}
]
};
}
fitAllMarkers() {
this.map.fitToCoordinates(this.state.MARKERS, {
edgePadding: DEFAULT_PADDING,
animated: true,
});
}
render() {
return (
<View style={styles.container}>
<MapView
ref={ref => {
this.map = ref;
}}
style={styles.map}
initialRegion={this.state.region}
onMapReady={this.fitAllMarkers.bind(this)}
>
{this.state.MARKERS.map((marker, i) => (
<Marker key={i} identifier={`id${i}`} coordinate={marker}
description={marker.description}>
</Marker>
))}
</MapView>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={() => this.fitAllMarkers()}
style={[styles.bubble, styles.button]}
>
<Text>Fit All Markers</Text>
</TouchableOpacity>
</View>
</View>
);
}
I need your help to know how to display GPS coordinates in a MapView.
I want to track a person's location from gps coordinates (longitude and latitude).
I tried too much to recover the coordinates in a MapView but I did not arrive to do it, I am blocked.
So, I get the coordinates from a web service and I display them in a TextView.
This is my code:
import React, { Component } from 'react';
import { Constants, Location, Permissions } from 'expo';
import { Card } from 'react-native-paper';
import { Polyline } from 'react-native-maps';
import {
StyleSheet,
Platform,
View,
ActivityIndicator,
FlatList,
Text,
Image,
TouchableOpacity,
Alert,
YellowBox,
AppRegistry,
Button,
} from 'react-native';
export default class gps extends Component {
static navigationOptions = ({ navigation }) => {
return {
title: 'Suivi GPS',
headerStyle: {
backgroundColor: 'transparent',
},
headerTitleStyle: {
fontWeight: 'bold',
color: '#000',
zIndex: 1,
fontSize: 18,
lineHeight: 25,
fontFamily: 'monospace',
},
};
}
state = {
mapRegion: null,
dat: '',
};
GetItem() {}
componentDidMount() {
this.webCall();
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 0.5,
width: '100%',
backgroundColor: '#000',
}}
/>
); //
};
webCall = () => {
return fetch('http://first-ontheweb.com/onLineSenior/pos.php')
.then(response => response.json())
.then(responseJson => {
this.setState({
isLoading: false,
dataSource: responseJson,
});
})
.catch(error => {
console.error(error);
});
};
render() {
if (this.state.isLoading) {
return (
<View
style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" />
</View>
);
}
return (
<View style={styles.map}>
<FlatList
data={this.state.dataSource}
ItemSeparatorComponent={this.FlatListItemSeparator}
renderItem={({ item }) => (
<View>
<Text style={styles.textView}>Longitude :</Text>
<Text style={styles.textView}>{item.longitude}</Text>
<Text style={styles.textView}>Latitude :</Text>
<Text style={styles.textView}>{item.latitude}</Text>
</View>
)}
keyExtractor={(index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject,
},
});
So, I want to display the GPS coordinates in a MapView.
Thanks.
You can do something like this:
first import the mapView:
import MapView from "react-native-maps";
Then:
state = {
focusedLocation: {
latitude: 37.7900352, //or your coordinates
longitude: -122.4013726, //or your coordinates
latitudeDelta: 0.0122,
longitudeDelta:
Dimensions.get("window").width /
Dimensions.get("window").height *
0.0122
}
};
render() {
let marker = null;
if (this.state.locationChosen) {
marker = <MapView.Marker coordinate={this.state.focusedLocation} />;
}
return (
let marker = <MapView.Marker coordinate={this.state.focusedLocation} />;
<View style={styles.container}>
<MapView
initialRegion={this.state.focusedLocation}
style={//map style here}
>
{marker}
</MapView>
</View>
);
}
you need to install react-native-maps package than
import MapView from 'react-native-maps';
Rendering a Map with an initial region
<MapView
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
/>
Using a MapView while controlling the region as state
getInitialState() {
return {
region: {
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
},
};
}
onRegionChange(region) {
this.setState({ region });
}
render() {
return (
<MapView
region={this.state.region}
onRegionChange={this.onRegionChange}
/>
);
}
Rendering a list of markers on a map
import { Marker } from 'react-native-maps';
<MapView
region={this.state.region}
onRegionChange={this.onRegionChange}
>
{this.state.markers.map(marker => (
<Marker
coordinate={marker.latlng}
title={marker.title}
description={marker.description}
/>
))}
</MapView>
you can find more in the documention here.
https://github.com/react-native-community/react-native-maps
I use DefaultMarkers to get location from user.
I have a button and a function. In the function I use a code to show latitude in console. Now When I press the button, in console not happening but for second press I can see latitude in console.
If I change location and try again, I should press button for twice to see latitude in console.
constructor(props){
super(props);
this.state={
markers: [],
}
}
onMapPress(e) {
this.setState({
markers: [
{
coordinate: e.nativeEvent.coordinate,
key: 0,
},
],
});
}
SaveAddress=()=>{
console.log(JSON.stringify(this.state.markers[0].coordinate.latitude);
}
<Button onPress={this.SaveAddress}>
<Text>Save</Text>
</Button>
<MapView
style={styles.map}
initialRegion={{
latitude: 28.95761453,
longitude: 50.83710976,
latitudeDelta: 0.0040,
longitudeDelta: 0.0040,
}}
provider={this.props.provider}
onPress={(e) => this.onMapPress(e)}
>
{this.state.markers.map(marker => (
<Marker
key={marker.key}
coordinate={marker.coordinate}
/>
))}
</MapView>
Because, when you first-time press that button to execute this function
SaveAddress=()=>{console.log(JSON.stringify(this.state.markers[0].coordinate.latitude);}
The state is empty so you don't get any value. On your first press, it just starts to save the state and start to render. But on your second press, rendering is complete and the states became set then you got the value.
You can do instead
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, WebView, StyleSheet,KeyboardAvoidingView, ActivityIndicator,Platform,TextInput,Dimensions} from 'react-native'
import MapView, { PROVIDER_GOOGLE, Region,Marker } from 'react-native-maps';
export default class App extends React.Component {
constructor(props){
super(props);
this.state={
markers: [
{
coordinate: { latitude: 28.95761453,
longitude: 50.83710976,
},
key: 0,
},
],
}
}
onMapPress(e) {
this.setState({
markers: [
{
coordinate: e.nativeEvent.coordinate,
key: 0,
},
],
});
}
SaveAddress=()=>{
console.log(JSON.stringify(this.state.markers[0].coordinate.latitude))
}
render() {
return (
<View style={{flex:1}}>
<MapView
style={[styles.map]}
initialRegion={{
latitude: 28.95761453,
longitude: 50.83710976,
latitudeDelta: 0.0040,
longitudeDelta: 0.0040,
}}
// onMapReady={this.onMapReady}
provider={ PROVIDER_GOOGLE}
onPress={(e) => this.onMapPress(e)}
>
{this.state.markers.map(marker => (
<Marker
key={marker.key}
coordinate={marker.coordinate}
/>
))}
</MapView>
<TouchableOpacity onPress={()=>this.SaveAddress()}>
<Text>Save</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject,
},
});
I have implemented a MapView with react-native-maps. I'm trying to change Marker's pinColor by clicking on it.
Note: I have large amounts of markers. So I don't think refreshing all view can be a good solution. I need directly change the selected marker's color.
I didn't find how to do it. I tried below code:
class TestMap extends React.Component {
constructor(props) {
this.state = {
testColor: "#FFFFFF",
userLatitude:0,
userLongitude:0,
data:[]
}
}
render() {
return (
<MapView
provider={PROVIDER_GOOGLE}
showsTraffic={true}
showsBuildings={true}
toolbarEnabled={true}
loadingEnabled={true}
style={styles.map}
initialRegion={{
latitude: this.state.userLatitude,
longitude: this.state.userLongitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA
}}
onPoiClick={this.onPoiClick}
showsUserLocation={true}
followsUserLocation={true}
showsMyLocationButton={true}
loadingBackgroundColor="#FEA405"
loadingIndicatorColor="white"
onLongPress={e => this.onMapPress(e)}
enableZoomControl
>
{this.ListMarkers()}
</MapView>
)};
ListMarkers() {
return this.state.data.map((data, i) => {
return (
<Marker
key={i}
onPress={e => this.onPressMarker(e, i, data)}
coordinate={{
longitude: data.LONGITUDE,
latitude: data.LATITUDE
}}
pinColor={this.state.testColor}
/>
)}
)};
onPressMarker(e, index, data) {
this.setState({testColor:"#000000"});
}
}
I expect the color of marker should change after clicking on it but it is not working.
Thanks for your help.
You can set the selected pin in the state and use a different style in that case, if you have some id in your data you can use that value instead of the index:
constructor(props) {
this.state = {
selectedPin: -1,
}
}
ListMarkers = () => {
return this.state.data.map((data, i) => {
return (
<Marker
key={i}
onPress={e => this.onPressMarker(e, i, data)}
coordinate={{
longitude: data.LONGITUDE,
latitude: data.LATITUDE
}}
pinColor={ i === this.state.selectedPin ? '#FF0000' : '#FFFFFF'}
/>
)}
)};
onPressMarker = (e, index, data)=> {
this.setState({selectedPin:index});
}