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)