react-native-maps conditional markers - react-native

I have a map of markers that renders each marker in an array of coordinates. I am trying to render markers conditionally based on a key I give the marker. You can see exactly how I am trying to do this by looking at my snack example here or I have posted the code below.
Thank you, I appreciate it more than you know.
export default class Map extends React.Component {
markers = [];
state = {
coordinates: [
{
name: '1',
latitude: 36.212111515965525,
longitude: -81.67527588876025,
status: 'busy',
},
{
name: '2',
latitude: 36.21754431261142,
longitude: -81.68598350040361,
status: 'open',
},
{
name: '3',
latitude: 36.21744712906634,
longitude: -81.68168562889075,
status: 'busy',
},
{
name: '4',
latitude: 36.219352000280495,
longitude: -81.68559146421954,
status: 'open',
},
],
};
render() {
return (
<View style={{ ...StyleSheet.absoluteFillObject }}>
<MapView
style={styles.map}
provider={PROVIDER_GOOGLE}
showsUserLocation={true}
showsMyLocationButton={true}
ref={(map) => (this._map = map)}
initialRegion={{
latitude: 36.212111515965525,
longitude: -81.67527588876025,
latitudeDelta: 0.05,
longitudeDelta: 0.05
}}>
{this.state.coordinates.map((marker, index) => (
if(marker.status == 'busy'){
<Marker
key={marker.name}
ref={(ref) => {this.markers[index] = ref;}}
onPress={() => this.onMarkerPress(marker, index)}
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}>
<Image
source={require('./assets/blueMarker.png')}
style={{ height: scale(50), width: scale(50) }}
/>
</Marker>
} else {
<Marker
key={marker.name}
ref={(ref) => {this.markers[index] = ref;}}
onPress={() => this.onMarkerPress(marker, index)}
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}>
</Marker>
}
))}
</MapView>
</View>
);
}
}

You're not using correct JSX syntax. You can't use if-then-else, use ternary operator instead.
{ this.state.coordinates.map((marker, index) => (
marker.status == 'busy' ?
<Marker
key={marker.name}
ref={(ref) => {this.markers[index] = ref;}}
onPress={() => this.onMarkerPress(marker, index)}
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}>
<Image
source={require('./assets/blueMarker.png')}
style={{ height: scale(50), width: scale(50) }}
/>
</Marker>
:
<Marker
key={marker.name}
ref={(ref) => {this.markers[index] = ref;}}
onPress={() => this.onMarkerPress(marker, index)}
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}>
</Marker>
))}

Here, In JSX we are allowed to render components only.
If We have to render something conditionally, we can use ternary operators for that.
Here I can see in the code that you have used If...Else...
Solution for your code:
{
this.state.coordinates.map((marker, index) => (
marker.status == 'busy'
?
<Marker
key={marker.name}
ref={(ref) => {this.markers[index] = ref;}}
onPress={() => this.onMarkerPress(marker, index)}
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}>
<Image
source={require('./assets/blueMarker.png')}
style={{ height: scale(50), width: scale(50) }}
/>
</Marker>
:
<Marker
key={marker.name}
ref={(ref) => {this.markers[index] = ref;}}
onPress={() => this.onMarkerPress(marker, index)}
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}>
</Marker>
))
}

Related

Mapview only works on expo client and close the application when built in apk

import MapView, { Marker, PROVIDER_GOOGLE } from "react-native-maps"
  const Location = (props)=>{
    const { states } = useContext(Context)
    const place = states.place
return(
<ImageBackground
style={{flex:1}}
source={require('../../img/mypoint-wallpaper.jpg')}>
<View style={styles.container}>
<MapView style={{
width: Dimensions.get('window').width,
height: Dimensions.get('window').height
}}
provider={PROVIDER_GOOGLE}
showsUserLocation={true}
showsMyLocationButton={true}
initialRegion={{
latitude: place && place.latitude,
longitude: place && place.longitude,
longitudeDelta: 0.01,
latitudeDelta: 0.01
}}>
{
(place.latitude && place.longitude) ?
<Marker
title={place.nome}
coordinate={{
latitude: place.latitude,
longitude: place.longitude
}}/>
: null
}
</MapView>
</View>
</ImageBackground>
)
}

How can I pass a reference of a mapview to another component?

I have a map view, and in another componenet, I would like to be able to have a function that animates that mapview. That function would need a reference to my map view. How can I access my maps reference inside another component?
I have a snack expo that reproduces my problem exactly here as well as some code below. Please note which files are classes and which are functions. The files are too big in my projects, I do not want to change them
EDIT: Could I use some sort of state library such as Context to store the ref?
export default function App() {
return (
<View style={styles.container}>
<Map/>
<AnimateMapButton/>
</View>
);
}
I cant access this._map for obvious reasons. How can I access this?
export default class AnimateMapButton extends React.Component {
goToLocation = () => {
this._map.animateToRegion({
latitude: 103.1561,
longitude: -47.1651,
latitudeDelta: 0.0025,
longitudeDelta: 0.0025,
})
}
render() {
return (
<View style={{height: 75, width: 200, backgroundColor: 'red', position: 'absolute', top: 100}}>
<TouchableOpacity onPress={() => this.goToLocation()}>
<Text style={{fontSize: 20, }}>Click to animate the map</Text>
</TouchableOpacity>
</View>
);
}
}
export default class Map extends React.Component {
render(){
return (
<View style={styles.container}>
<MapView
style={styles.map}
ref={map => this._map = map}
/>
</View>
);
}
}
I suggest you use React.forwardRef in such scenarios.
map.js
export default React.forwardRef((props, ref) => {
return (
<View style={styles.container}>
<MapView
ref={ref}
style={styles.map}
/>
</View>
);
})
animatemapbutton.js
export default class AnimateMapButton extends React.Component {
render() {
return (
<View style={{height: 75, width: 200, backgroundColor: 'red', position: 'absolute', top: 100}}>
<TouchableOpacity onPress={() => this.props.onGotoLocation()}>
<Text style={{fontSize: 20, }}>Click to animate the map</Text>
</TouchableOpacity>
</View>
);
}
}
App.js
export default function App() {
const _mapRef = React.createRef();
goToLocation = () => {
_mapRef.current.animateToRegion({
latitude: 103.1561,
longitude: -47.1651,
latitudeDelta: 0.0025,
longitudeDelta: 0.0025,
})
}
return (
<View style={styles.container}>
<Map ref={_mapRef}/>
<AnimateMapButton onGotoLocation={goToLocation} />
</View>
);
}
You have to use a combination of reference and event callback method in the root component like this -
App.js
export default function App() {
const mapRef = React.useRef();
const goToLocation = () => {
mapRef.current.animateToRegion({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
})
}
return (
<View style={styles.container}>
<Map mapRef={mapRef} />
<AnimateMapButton goToLocation={goToLocation} />
</View>
);
}
animatemapbutton.js
export default function Animatemapbutton({ goToLocation }) {
return (
<TouchableOpacity
style={{ height: 75, width: 200, backgroundColor: 'red', position: 'absolute', top: 100 }}
onPress={() => goToLocation()}
>
<Text style={{fontSize: 20, }}>Click to animate the map</Text>
</TouchableOpacity>
);
}
map.js
export default function Map({ mapRef }) {
return (
<View style={styles.container}>
<MapView
ref={mapRef}
style={styles.map}
/>
</View>
);
}

react native navigation nested screen

i have screen with 2 tabs
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Main" component={Main}/>
<Tab.Screen name="Chat" component={Chat}/>
</Tab.Navigator>
</NavigationContainer>
Screen Chat very simple and it works :
const Chat = () => {
return (
<View>
<Text>Chat</Text>
</View>
);
};
export default Chat;
But in first screen Main i have nested screen Map
const Main = () => {
return (
<Map/>
);
};
export default Main;
Tell me pls how nested screens works, because i have an error :
Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app
Component Map:
export const Map = () => {
return (
<View style={styles.container}>
<MapView
provider={PROVIDER_GOOGLE} // remove if not using Google Maps
style={styles.map}
region={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.015,
longitudeDelta: 0.0121,
}}
>
<Marker
title="title"
description='descr'
coordinate={{
latitude: 37.78825,
longitude: -122.4324,
}}>
<View style={{backgroundColor: "red", padding: 10}}>
<Text>SF</Text>
</View>
</Marker>
</MapView>
</View>
);
};
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
height: '100%',
width: '100%',
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
...StyleSheet.absoluteFillObject,
},
});
problem was in wrong import MapView!

How to go to my current location using custom button in react-native-maps?

I am using react-native-maps on android. I put a custom button clicking on which should go to supplied coordinates (my current location)
<MapView
ref={(map) => { this.map = map; }}
provider={PROVIDER_GOOGLE}
style={{ height: '100%', width: '100%' }}
annotations={markers}
showsUserLocation={true}
showsMyLocationButton={true}
initialRegion={this.state.region}
onRegionChangeComplete={this.onRegionChange}
>
my button -
<TouchableOpacity onPress={this.gotToMyLocation} style={[Style.alignJustifyCenter, {
width: 60, height: 60,
position: "absolute", bottom: 20, right: 20, borderRadius: 30, backgroundColor: "#d2d2d2"
}]}>
<Image
style={{ width: 40, height: 40 }}
source={Images.myLocation}
/>
</TouchableOpacity>
gotToMyLocation method -
gotToMyLocation(){
console.log('gotToMyLocation is called')
navigator.geolocation.getCurrentPosition(
({ coords }) => {
console.log("curent location: ", coords)
console.log(this.map);
if (this.map) {
console.log("curent location: ", coords)
this.map.animateToRegion({
latitude: coords.latitude,
longitude: coords.longitude,
latitudeDelta: 0.005,
longitudeDelta: 0.005
})
}
},
(error) => alert('Error: Are location services on?'),
{ enableHighAccuracy: true }
)
}
console.log(this.map) always shows undefined.
I want to move map to my current location when clicking the button.
Default my location button
showsUserLocation={true}
showsMyLocationButton={true}
Example:
<MapView
provider={PROVIDER_GOOGLE}
showsUserLocation={true}
showsMyLocationButton={true}
style={{
...StyleSheet.absoluteFillObject,
width: '100%',
}}
initialRegion={{
latitude: targetLocation.latitude,
longitude: targetLocation.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}>
A custom button
<MaterialIcons
style={style.myLocationIcon}
name="my-location"
onPress={() => {
dispatch(settingActions.getLocation());
mapRef.current.animateToRegion({
latitude: myLatitude,
longitude: myLongitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
}}
/>
For this you need to define mapRef
export const mapRef = React.createRef();
return(
<MapView
ref={mapRef}
Animation
mapRef.current.animateToRegion({ will take care of animation while you switch from one location to another.
Actually i found out a silly mistake where binding the method would make it work. may be useful to someone.
this.gotToMyLocation = this.gotToMyLocation.bind(this);
move your function gotToMyLocation:
if Using Class - in class before render()
or
if using function - use function gotToMyLocation(){...} and don't use this

How can I create a mapView

I try to create a MapView, but when I enter the page containing it I get an error.
<View>
<MapView style={{ flex: 1, height: 500 }}
zoomEnabled={false}
scrollEnabled={false}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<Marker
coordinate={{ latitude: 37.78825, longitude: -122.4324 }}
title={'title'}
description={'description'}
/>
</MapView>
</View>