If you're building a property or travel app with React Native and want to show each listing on a map, this quick guide walks you through adding a simple Google Map — starting with a fixed location and ending with live coordinates from your Supabase database.
🧩 Step 1. Install the Map Library
Expo supports react-native-maps
out of the box. Just install it:
npx expo install react-native-maps
This gives you access to an interactive Google Map view and markers for iOS and Android.
🏠 Step 2. Create a Simple Fixed Map
Before connecting to data, start with something static.
import React from 'react';
import { StyleSheet, View } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
export default function HouseDetails() {
const region = {
latitude: -36.8485, // Auckland
longitude: 174.7633,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
};
return (
<View style={styles.container}>
<MapView style={styles.map} initialRegion={region}>
<Marker
coordinate={{ latitude: -36.8485, longitude: 174.7633 }}
title="Sample Home"
description="123 Queen Street, Auckland"
/>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
map: { width: '100%', height: 300, borderRadius: 12 },
});
That’s already enough to render a map centered on Auckland — no API key, no fuss.
⚙️ Step 3. Load Coordinates from Supabase
Let’s make it dynamic by reading each house’s latitude and longitude from your Supabase table.
import React, { useEffect, useMemo, useState } from 'react';
import { ActivityIndicator, StyleSheet, View } from 'react-native';
import { useLocalSearchParams } from 'expo-router';
import MapView, { Marker } from 'react-native-maps';
import { supabase } from '@/lib/supabase';
type House = {
id: string;
title: string | null;
address: string | null;
latitude: number | null;
longitude: number | null;
};
export default function HouseDetails() {
const { id } = useLocalSearchParams<{ id: string }>();
const [house, setHouse] = useState<House | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let mounted = true;
(async () => {
const { data, error } = await supabase
.from('houses')
.select('id, title, address, latitude, longitude')
.eq('id', id)
.single();
if (mounted) {
if (error) console.warn('Failed to load house:', error.message);
setHouse(data ?? null);
setLoading(false);
}
})();
return () => { mounted = false; };
}, [id]);
const region = useMemo(() => {
if (!house?.latitude || !house?.longitude) return null;
return {
latitude: house.latitude,
longitude: house.longitude,
latitudeDelta: 0.02,
longitudeDelta: 0.02,
};
}, [house?.latitude, house?.longitude]);
if (loading)
return <View style={styles.center}><ActivityIndicator /></View>;
if (!region)
return <View style={styles.center} />;
return (
<View style={styles.container}>
<MapView
key={`${region.latitude},${region.longitude}`}
style={styles.map}
initialRegion={region}
showsUserLocation={false}
showsCompass={false}>
<Marker
coordinate={region}
title={house?.title ?? 'Home'}
description={house?.address ?? ''}
/>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
center: { flex: 1, alignItems: 'center', justifyContent: 'center' },
map: { width: '100%', height: 300, borderRadius: 12 },
});
Why use useMemo()
?
When coordinates come from asynchronous data, useMemo()
ensures the region object stays stable between renders. Without it, the map might flicker or reset each time the component updates.
🌀 Without useMemo()
If your region object is recreated on every render (e.g., defined inline like this):
const region = {
latitude: house.latitude,
longitude: house.longitude,
latitudeDelta: 0.02,
longitudeDelta: 0.02,
};
then React sees it as a new object each time — even if the coordinates haven’t changed.
So every time your component re-renders (for example, when: some unrelated state changes, data finishes loading, a parent component re-renders), the receives a new initialRegion prop and may reset its camera to the starting coordinates again.
That’s what looks like a “flicker” — the map seems to reload or jump back to the initial position.
** 🧠 With useMemo()
By memoizing the region:
const region = useMemo(() => ({
latitude: house.latitude,
longitude: house.longitude,
latitudeDelta: 0.02,
longitudeDelta: 0.02,
}), [house.latitude, house.longitude]);
React will reuse the same object reference until the latitude or longitude actually changes — so the map stays still, no flicker.
✅ Wrap-Up
You now have a dynamic, interactive map inside your React Native app that reads real data from Supabase.
For small projects, this pattern is simple, fast, and deploy-ready — no Google Cloud setup required.
Top comments (0)