React Native Maps not rerendering Markers on iOS - react-native

I am using react native maps for displaying a map in my application, and this map should display markers that are fetched from a database online. When the map is mounted, and after fetching the marker data location points, I am updating a state containing the array of marker points, however, the markers do not get rendered after setting the state. Is there any work around in this? Here's a sample code:
P.S. This only occurs in iOS.
const [markerPoints, setMarkerPoints] = useState([])
useEffect(() => {
getMarkerPoints()
}, [])
const getMarkerPoints = callback => {
axios
.get(
'some end point',
)
.then(res => {
if (res.status === 200) {
setMarkerPoints(res.data.results)
}
})
.catch(error => {
console.log(error)
})
}
const renderMarkers = () => {
return markerPoints.map((place, index) => {
return (
<Marker
key={index}
coordinate={{
latitude: place.geometry.location.lat,
longitude: place.geometry.location.lng,
}}
/>
)
}
}
return (
<MapView
ref={map}
provider={PROVIDER_GOOGLE}
style={styles.map}
region={curRegion}
showsUserLocation={true}
showsMyLocationButton={false}
onRegionChangeComplete={onMapRegionChangeComplete}
customMapStyle={mapStyles}
>
{renderMarkers()}
</MapView>
)

Related

Route planning problem with openrouteservice-js: success result but no route planning react native

I try to define a route by clicking on a marker available on my map. My goal is to define a route, as soon as I click on a marker. My default origin is my position. I use Polyline to display itinerary.
The api of openrouteservice marks well "sucess".
DEMO : GIFDemo
SCREENSHOT : screenshotConsole
I use : "react-native": "0.70.5", "react-native-maps": "^1.3.2", "openrouteservice-js": "^0.2.0"
My code gets locations from a firebase and displays the markers on the map. It is supposed to display a route between my position and the marker I selected when I click on the find route button.
IMPORT :
import React, { useEffect, useMemo, useState } from "react";
import { StyleSheet, Text, View, Button, Linking } from "react-native";
import { StatusBar } from "expo-status-bar";
import * as Location from "expo-location";
import MapView, { Marker, Polyline, PROVIDER_GOOGLE } from "react-native-maps";
import { Alert } from "react-native";
import { enableLatestRenderer } from "react-native-maps";
import { getFriends } from "../commons/firebaseConfig";
import Modal from "react-native-modal";
import { OPENROUTE_SERVICE_API_KEY } from "../commons/contants";
const openrouteservice = require("openrouteservice-js");
My state's
const Planisphere = () => {
const [location, setLocation] = useState(null);
const [errorMsg, setErrorMsg] = useState(null);
const [mapRef, setMapRef] = useState(null);
const [locationAccepted, setLocationAccepted] = useState(false);
const [subscription, setSubscription] = useState(null);
const [permissions, setPermissions] = useState(null);
const [friends, setFriends] = useState([]);
const [selectedMarker, setSelectedMarker] = useState(null);
enableLatestRenderer();
track location in realtime
// track position in realtime
useEffect(() => {
const fetchLocation = async () => {
if (permissions === "granted") {
const watcher = await Location.watchPositionAsync(
{ accuracy: Location.Accuracy.BestForNavigation },
(location) => {
setLocation(location);
setLocationAccepted(true);
}
);
setSubscription(watcher);
}
};
fetchLocation();
return () => {
if (subscription) {
subscription.remove();
}
};
}, [permissions]);
// get friends ( longitude, latitude, title) from firebase
useEffect(() => {
async function fetchFriends() {
const friends = await getFriends();
setFriends(friends);
console.log(friends);
}
fetchFriends();
}, []);
provide openrouteserviceapikey
// provide openrouteserviceapikey
const Directions = new openrouteservice.Directions({
api_key: "",
});
Handle Selected marker
const handleMarkerPress = (marker) => {
setSelectedMarker(marker);
console.log("markerselected", marker);
};
display route if a marker is selected and if there is location;
openrouteservice function to calculate with start ( my position ) and end (position of marker);
// display route if a marker is selected and if there is location
const handleRoute = () => {
if (!selectedMarker || !location) return;
// openrouteservice function to calculate with start ( my position ) and end (position of marker)
Directions.calculate({
coordinates: [
[location.coords.longitude, location.coords.latitude],
[selectedMarker.coords.longitude, selectedMarker.coords.latitude],
],
profile: "driving-car",
format: "json",
})
.then(function (response) {
// console.log("response", response);
const geometry = response.features[0].geometry;
console.log("geometry", geometry);
const coordinates = geometry.coordinates;
// to display itinerary
return (
<Polyline
coordinates={coordinates}
strokeWidth={4}
strokeColor={"#000"}
/>
);
})
.catch((error) => {
console.log(error);
});
};
Return : MapView with initial regions and other parameters; My marker position and Marker from firebase firestore database; A button to trigger the itinerary when marker is selected.
return (
<View style={styles.container}>
<StatusBar style="auto" />
{location && (
<MapView
provider={PROVIDER_GOOGLE}
ref={(ref) => setMapRef(ref)}
style={styles.map}
minZoomLevel={5}
maxZoomLevel={18}
initialRegion={{
latitude: location.coords.latitude,
longitude: location.coords.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
// my location
<Marker
coordinate={{
latitude: location.coords.latitude,
longitude: location.coords.longitude,
}}
title={"Your location"}
/>
// marker position
{friends.map((friend) => (
<Marker
key={friend.id}
coordinate={{
latitude: friend.coords.latitude,
longitude: friend.coords.longitude,
}}
title={friend.title}
description={friend.description}
// when marker is selected
onPress={() => handleMarkerPress(friend)}
/>
))}
</MapView>
)}
<View>
<Text style={styles.paragraph}>{text}</Text>
</View>
<View style={styles.bord}>
{locationAccepted && (
<View style={styles.buttonContainer} onPress={() => setOpacity(1)}>
// button to show itinerary
<Button
title="Find route"
onPress={handleRoute}
disabled={!selectedMarker}
/>
</View>
)}
</View>
</View>
);
};
export default Planisphere;

React Native Maps onMapReady getMapBoundaries

I haven't been able to find anything to fix it. I'm using react-native maps
const finalMap = () => {
return(
<SafeAreaView style={styles.authContainerStyles}>
<MapView
style={styles.map}
provider={PROVIDER_GOOGLE}
region={{
latitude: !!userLocation ? userLocation.coords.latitude : 43.60271848664041,
longitude: !!userLocation
? userLocation.coords.longitude
: -116.20149258821509,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
}}
onMapReady = {this.map.getMapBoundaries()}
>
Try the below code or run this Snack here: https://snack.expo.io/Cu5qYmcZm
function Map() {
const [mapRef, updateMapRef] = useState(null);
const getBoundaries = () => {
if (mapRef === null) {
return;
}
mapRef
.getMapBoundaries()
.then((res) => {
console.log(res);
})
.catch((err) => console.log(err));
};
return (
<View>
<MapView
ref={(ref) => updateMapRef(ref)}
onMapReady={() => getBoundaries()}
/>
</View>
);
}
You need to store the ref to the map, so you can refer back to it later (when you check the boundaries). You could also store this in the state. Then after the map is ready, the event is fired and using the ref we can refer back to it and query the info about the boundaries.

How do you use getMapBoundaries with React Naitve Maps

Currently creating an application for a company. The user of the application is displayed on the map, and their pets are supposed to display on the map as well. In order to do that I need the boundaries of the map. I am using react-native-maps and it as a built function getMapBoundaries. When I use the function I have gotten the following errors
function getMapBoundaries does not exist
And the latest
Cannot set property map of undefined.
Here is what I have
const AppMapView = () => {
const handleRegionChange = async region => {
//I get an error for the statement below
console.log(
await this.map.getMapBoundaries()
.then(response => {
return response
})
)
};
handleRegionChange()
return (
<View style={styles.container}>
<MapView
ref={ref => {
this.map = ref;
}}
>
<Marker
coordinate={...}
>
<Image {...} />
</Marker>
</MapView>
</View>
)
};
export default AppMapView;
A code example would be much appreciated.
If anyone is still searching for the answer, this works:
<MapView
ref={mapView}
onRegionChangeComplete={async (val) => {
console.log(await mapRef.current.getMapBoundaries())
}
>
<Marker
coordinate={...}
>
</Marker>
</MapView>
You can get it from current of the ref
This code works for me:
mapRef = null;
onRegionChangeComplete = async () => {
console.log("onRegionChangeComplete", await this.mapRef.getMapBoundaries());
};
<MapView
ref={(ref) => {
this.mapRef = ref;
}}
onRegionChangeComplete={this.onRegionChangeComplete}
<Marker
coordinate={...}
>
</Marker>
</MapView>

How can I render my markers inside the ClusteredMapView?

I am trying to render the markers inside the component <ClusteredMapView/> but it do not happen, just render the marker with none markers...
Bellow some code:
render() {
return (
<ClusteredMapView
style={{ flex: 1 }}
data={this.state.data}
initialRegion={INIT_REGION}
ref={r => {
this.map = r;
}}
renderMarkerS={this.renderMarkerS}
renderCluster={this.renderCluster}
/>
);
}
}
here is the renderMarkers function:
renderMarkerS = item =>
this.state.markers.map((marker, index) => {
console.log('Location picker Marker', coords);
const coords = {
location: {
latitude: JSON.parse(item.latitude),
longitude: JSON.parse(item.longitude),
},
};
return (
<Marker
onPress={this.pickLocationHandler}
ref={mark => (marker.mark = mark)}
key={index || Math.random()}
title={'Parada'}
description={marker.hora}
tracksViewChanges={!this.state.initialized}
{...this.props}
pinColor={'tomato'}
coordinate={JSON.parse(item.location)}
//coordinate={coords}
>
{this.props.children}
</Marker>
);
});
With:
componentDidMount() {
return fetch(
'https://gist.githubusercontent.com/MatheusCbrl/bba7db1c0dbc68be2f26d5c7e15649b6/raw/0fab4ea3b493dcd15e95f172cd0a251724efbc45/ParadasDiurno.json'
)
.then(response => response.json())
.then(responseJson => {
// just setState here e.g.
this.setState({
data: responseJson,
isLoading: false,
});
})
.catch(error => {
console.error(error);
});
}
My data is:
[
{
"id": "1",
"location": {
"latitude": "-29.2433828",
"longitude": "-51.199249"
},
"hora": "03:55:00 PM"
},
Some one can help me?
Here is the intere code to your view: https://snack.expo.io/#matheus_cbrl/clusters
I got the follow error:
Device: (3:18096) No cluster with the specified id.
Device: (3:5314) TypeError: t.props.renderMarker is not a function. (In 't.props.renderMarker(e.properties.item)', 't.props.renderMarker' is undefined)
This error is located at:
in e
in MyClusteredMapView
in RCTView
in RCTView
in n
in n
in v
in RCTView
in RCTView
in c
Device: TypeError: t.props.renderMarker is not a function. (In 't.props.renderMarker(e.properties.item)', 't.props.renderMarker' is undefined)
Prettier
Editor
Expo
renderMarker is a function that render just 1 marker. Besides, you use this.state.data for markers but you didn't update it. You could try below
componentDidMount() {
return fetch(
'https://gist.githubusercontent.com/MatheusCbrl/bba7db1c0dbc68be2f26d5c7e15649b6/raw/0fab4ea3b493dcd15e95f172cd0a251724efbc45/ParadasDiurno.json'
)
.then(response => response.json())
.then(responseJson => {
// just setState here e.g.
this.setState({
data: responseJson, <-- update here
isLoading: false,
});
})
.catch(error => {
console.error(error);
});
}
renderCluster = (cluster, onPress) => {
const pointCount = cluster.pointCount,
coordinate = cluster.coordinate;
const clusterId = cluster.clusterId;
return (
<Marker key={clusterId} coordinate={coordinate} onPress={onPress}>
<View style={styles.myClusterStyle}>
<Text style={styles.myClusterTextStyle}>
{pointCount}
</Text>
</View>
</Marker>
);
};
renderMarker(marker) {
console.log('Location picker Marker', marker.location);
const coords = {
latitude: parseFloat(marker.location.latitude),
longitude: parseFloat(marker.location.longitude),
}
return (
<Marker
key={marker.id}
title={'Parada'}
description={marker.hora}
pinColor={'tomato'}
coordinate={coords}
/>
);
}
render() {
return (
<View style={{ flex: 1 }}>
<StatusBar hidden />
<ClusteredMapView
style={{ flex: 1 }}
data={this.state.data}
initialRegion={INIT_REGION}
ref={r => this.map = r}
renderMarker={this.renderMarker}
renderCluster={this.renderCluster}
/>
</View>
);
}

React Native Maps: Multiple Markers placed and state changed

I am currently working on an application that uses React Native Maps. I've seen their examples for putting multiple markers and how to change a marker's state when pressed, and I would like to be able to combine the two functions together. I want to be able to put down multiple markers, then change the state of individual markers when pressed. I've had success putting down multiple markers, but when pressed, all markers have their state changed. I'd like to know what to do so markers will have individual states changed when pressed. Thanks for all the help.
Here are the links to the examples of React Native Maps I used:
https://github.com/airbnb/react-native-maps/blob/master/example/examples/DefaultMarkers.js
https://github.com/airbnb/react-native-maps/blob/master/example/examples/MarkerTypes.js
Here's the code I currently have
const SPACE = 0.01;
let id = 0;
class MarkerTypes extends React.Component {
constructor(props) {
super(props);
this.state = {
marker1: true,
region: {
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
},
markers: [],
};
}
onMapPress(e) {
console.log(e)
this.setState({
markers: [
...this.state.markers,
{
coordinate: e.nativeEvent.coordinate,
key: id++,
marker1: true,
},
],
});
}
render() {
return (
<View style={styles.container}>
<MapView
provider={this.props.provider}
style={styles.map}
initialRegion={this.state.region}
onPress={(e) => this.onMapPress(e)}
>
{this.state.markers.map(marker => (
<MapView.Marker
key={marker.key}
})}
onPress={() => {
this.setState({ marker1: !this.state.marker1 })}
}
coordinate={marker.coordinate}
image={this.state.marker1 ? flagBlueImg : flagPinkImg}
>
</MapView.Marker>
))}
</MapView>
</View>
);
}
}
To change the image marker on the marker that is touched on the map you need to toggle the marker property on the marker inside the this.state.markers array, eg this.state.markers[0].marker1, currently you are toggling the this.state.marker1 which is shared by all markers
{this.state.markers.map((marker, index) => (
<MapView.Marker
key={marker.key}
onPress={() => {
const marker = this.state.markers[index]
marker.marker1 = !marker.marker1
this.setState({ markers: [
...this.state.markers.slice(0, index),
marker,
...this.state.markers.slice(index + 1)
]})}
}
coordinate={marker.coordinate}
image={marker.marker1 ? flagBlueImg : flagPinkImg}
>
</MapView.Marker>
))}
in this way each marker is using and updating it's own state in the array.