React Native Maps not showing Markers on Android, even though API data is fetched correctly
I'm building a React Native app to display location markers on a map using react-native-maps. I'm using the Google Maps provider on Android. My problem is that the map loads, but the markers are not visible, even though I can confirm that my API call is successful and returns a valid array of location data.
MapsScreen.jsx:-
import React, { useState, useEffect, useRef, useMemo } from "react";
import {
View,
Text,
StyleSheet,
ActivityIndicator,
Alert,
SafeAreaView,
TouchableOpacity,
StatusBar,
Modal,
} from "react-native";
import MapView, { Marker, Callout, PROVIDER_GOOGLE } from "react-native-maps";
import { useRoute, useNavigation } from "@react-navigation/native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { fetchMaps } from "../services/maps";
const StatusIndicator = ({ text }) => (
<SafeAreaView style={styles.statusContainer}>
<StatusBar barStyle="light-content" backgroundColor="#181d23" />
<ActivityIndicator size="large" color="#27F0C9" />
<Text style={styles.statusText}>{text}</Text>
</SafeAreaView>
);
const isValidCoord = (lat, lng) =>
Number.isFinite(lat) &&
Number.isFinite(lng) &&
Math.abs(lat) <= 90 &&
Math.abs(lng) <= 180;
const MapsAnalysis = () => {
const [points, setPoints] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
const [showInfo, setShowInfo] = useState(false);
const [mapReady, setMapReady] = useState(false);
const route = useRoute();
const navigation = useNavigation();
const { userId } = route.params;
const mapRef = useRef(null);
useEffect(() => {
const getLocations = async () => {
if (!userId) {
setError("User ID not found. Cannot fetch map data.");
setIsLoading(false);
return;
}
try {
setIsLoading(true);
setError(null);
const data = await fetchMaps(userId);
const formattedData = Array.isArray(data)
? data
.map((point) => {
const lat = Number(point.latitude);
const lng = Number(point.longitude);
return {
...point,
latitude: Number.isFinite(lat) ? lat : NaN,
longitude: Number.isFinite(lng) ? lng : NaN,
pleasantness:
point.pleasantness != null ? Number(point.pleasantness) : null,
eventfulness:
point.eventfulness != null ? Number(point.eventfulness) : null,
annoyance:
point.annoyance != null ? Number(point.annoyance) : null,
};
})
.filter((p) => isValidCoord(p.latitude, p.longitude))
: [];
console.log("Points to plot:", formattedData.length, formattedData.slice(0, 3));
setPoints(formattedData);
} catch (err) {
console.error("Failed to fetch map data:", err);
setError(err.message || "Could not load map data.");
Alert.alert("Error", err.message || "Could not load map data.");
} finally {
setIsLoading(false);
}
};
getLocations();
}, [userId]);
const coords = useMemo(
() => points.map((p) => ({ latitude: p.latitude, longitude: p.longitude })),
[points]
);
useEffect(() => {
if (!mapReady || !mapRef.current || coords.length === 0) return;
if (coords.length === 1) {
const p = coords[0];
mapRef.current.animateToRegion(
{
latitude: p.latitude,
longitude: p.longitude,
latitudeDelta: 0.02,
longitudeDelta: 0.02,
},
600
);
} else {
mapRef.current.fitToCoordinates(coords, {
edgePadding: { top: 100, right: 100, bottom: 100, left: 100 },
animated: true,
});
}
}, [mapReady, coords]);
if (isLoading) {
return <StatusIndicator text="Loading Map Data..." />;
}
if (error) {
return <StatusIndicator text={error} />;
}
if (points.length === 0) {
return <StatusIndicator text="No map points found for this user." />;
}
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle="light-content" backgroundColor="#181d23" />
<View style={styles.header}>
<TouchableOpacity onPress={() => navigation.goBack()} style={{ padding: 5 }}>
<Icon name="chevron-left" size={28} color="#fff" />
</TouchableOpacity>
<Text style={styles.headerTitle}>Analysis Map</Text>
<TouchableOpacity onPress={() => setShowInfo(true)} style={{ padding: 5 }}>
<Icon name="help-circle-outline" size={24} color="#fff" />
</TouchableOpacity>
</View>
<Modal transparent visible={showInfo} animationType="fade">
<View style={styles.overlay}>
<View style={styles.infoModalBox}>
<Text style={styles.infoTitle}>About The Map</Text>
<Text style={styles.infoText}>
This map shows the locations of all saved sound analyses. Tap on any pin to see the details of that specific analysis.
</Text>
<TouchableOpacity style={styles.closeBtn} onPress={() => setShowInfo(false)}>
<Text style={styles.closeText}>Got It</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
<MapView
ref={mapRef}
provider={PROVIDER_GOOGLE}
style={styles.map}
// Delhi
initialRegion={{
latitude: 28.6139,
longitude: 77.209,
latitudeDelta: 0.5,
longitudeDelta: 0.5,
}}
onMapReady={() => setMapReady(true)}
onLayout={() => setMapReady(true)}
>
{points.map((point, index) => (
<Marker
key={`${point.id ?? index}`}
coordinate={{ latitude: point.latitude, longitude: point.longitude }}
>
<Callout>
<View style={styles.calloutView}>
<Text style={styles.calloutTitle}>Analysis Details</Text>
<Text>
Pleasantness:{" "}
{typeof point.pleasantness === "number"
? point.pleasantness.toFixed(2)
: "N/A"}
</Text>
<Text>
Eventfulness:{" "}
{typeof point.eventfulness === "number"
? point.eventfulness.toFixed(2)
: "N/A"}
</Text>
<Text>
Annoyance:{" "}
{typeof point.annoyance === "number"
? point.annoyance.toFixed(2)
: "N/A"}
</Text>
</View>
</Callout>
</Marker>
))}
</MapView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#181d23",
},
map: {
flex: 1,
},
header: {
width: "100%",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingVertical: 14,
paddingHorizontal: 10,
paddingTop: 30,
backgroundColor: "#181d23",
},
headerTitle: {
fontSize: 20,
color: "#fff",
fontWeight: "bold",
},
statusContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#181d23",
},
statusText: {
marginTop: 20,
fontSize: 16,
color: "#B6BAC5",
},
calloutView: {
padding: 10,
width: 200,
},
calloutTitle: {
fontWeight: "bold",
fontSize: 16,
marginBottom: 5,
},
overlay: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.7)",
justifyContent: "center",
alignItems: "center",
},
infoModalBox: {
backgroundColor: "#2D2E32",
padding: 25,
borderRadius: 15,
width: "85%",
borderWidth: 1,
borderColor: "rgba(255, 255, 255, 0.1)",
},
infoTitle: {
color: "#FFFFFF",
fontSize: 18,
fontWeight: "bold",
textAlign: "center",
marginBottom: 15,
},
infoText: {
color: "#E0E0E0",
fontSize: 15,
lineHeight: 22,
marginBottom: 25,
},
closeBtn: {
backgroundColor: "#27F0C9",
paddingVertical: 12,
paddingHorizontal: 30,
alignSelf: "center",
borderRadius: 8,
},
closeText: {
color: "#181d23",
fontWeight: "bold",
fontSize: 16,
},
});
export default MapsAnalysis;