Skip to main content

useLocationUpdates

Real-time location update streaming hook. Subscribes to native events via NativeEventEmitter and provides locations as they arrive, without requiring manual polling. Also supports warning events and notification action callbacks.

import { useLocationUpdates } from '@gabriel-sisjr/react-native-background-location';

Platform: Android and iOS


Signature

function useLocationUpdates(
options?: UseLocationUpdatesOptions
): UseLocationUpdatesResult

Parameters

The hook accepts a single optional UseLocationUpdatesOptions object.

PropertyTypeDefaultDescription
tripIdstringSpecific trip ID to watch. If not provided, the hook watches updates for any active trip.
onLocationUpdate(location: Coords) => voidCallback fired for each new location received
onUpdateIntervalnumberundefinedThrottle interval in milliseconds for the onLocationUpdate callback. Locations are still collected and stored at the native update rate, but the callback is only executed at this interval.
onLocationWarning(warning: LocationWarningEvent) => voidCallback fired for service warnings (SERVICE_TIMEOUT, TASK_REMOVED, LOCATION_UNAVAILABLE)
onNotificationAction(event: NotificationActionEvent) => voidCallback fired when a notification action button is pressed
autoLoadbooleantrueWhether to automatically load existing locations from the database on mount

Note: All callbacks are accessed via refs internally, so passing inline functions is safe and does not cause re-subscriptions.


Return Value

Returns a UseLocationUpdatesResult object.

State Properties

PropertyTypeDescription
tripIdstring | nullCurrent trip ID being watched
isTrackingbooleanWhether location tracking is currently active
locationsCoords[]All locations received for the current trip, updated in real time as new locations arrive
lastLocationCoords | nullThe most recently received location
lastWarningLocationWarningEvent | nullThe most recent warning from the location service
isLoadingbooleanWhether data is being loaded from the database
errorError | nullLast error that occurred

Methods

MethodSignatureDescription
clearError() => voidReset the error state to null
clearLocations() => Promise<void>Clear all locations for the current trip from the database and reset the locations array
refreshLocations() => Promise<void>Manually reload locations from the database. Useful for pull-to-refresh or on-demand sync. No-op if no tripId is set.

Event Flow

The hook listens for three types of native events via NativeEventEmitter:

1. Location Updates (onLocationUpdate)

Native LocationService → SharedFlow → NativeEventEmitter → useLocationUpdates

Each location update:

  1. Is filtered by tripId (if a specific trip is being watched)
  2. Is appended to the locations array
  3. Updates lastLocation
  4. Fires the onLocationUpdate callback (subject to onUpdateInterval throttling)

2. Warning Events (onLocationWarning)

Native LocationService → SharedFlow → NativeEventEmitter → useLocationUpdates

Warning events are non-critical notifications about service state changes. They do not stop tracking.

Warning TypeMeaning
SERVICE_TIMEOUTAndroid 15+ foreground service timeout reached; service is restarting
TASK_REMOVEDApp was swiped from recents; tracking continues in background
LOCATION_UNAVAILABLEGPS signal lost or location services disabled

3. Notification Actions (onNotificationAction)

User taps notification button → BroadcastReceiver → SharedFlow → NativeEventEmitter → useLocationUpdates

Fired when the user taps an action button on the foreground service notification.


Hydration and Foreground Resume

Mount Hydration

When the component mounts (and autoLoad is true), the hook:

  1. Checks current tracking status
  2. Loads existing locations from the database for the active trip (one-time operation)
  3. Subscribes to real-time updates

This one-time DB read avoids the stale-data problem caused by batched database writes. After hydration, only real-time NativeEventEmitter events update the locations array.

Foreground Resume

When the app returns to the foreground (from background or inactive state), the hook re-loads locations from the database. This covers the scenario where the JS thread was destroyed (Activity/process killed) and real-time events were lost.

Manual Refresh

Call refreshLocations() for on-demand database sync, such as pull-to-refresh scenarios. This resets internal cleared-state tracking and performs a fresh DB read.


Usage

Real-time location display

import { useLocationUpdates } from '@gabriel-sisjr/react-native-background-location';

function LiveTrackingMap() {
const {
locations,
lastLocation,
isTracking,
lastWarning,
} = useLocationUpdates({
onLocationUpdate: (location) => {
console.log('New location:', location.latitude, location.longitude);
},
onLocationWarning: (warning) => {
console.warn(`[${warning.type}] ${warning.message}`);
},
});

return (
<View>
<Text>Tracking: {isTracking ? 'Active' : 'Inactive'}</Text>
<Text>Locations collected: {locations.length}</Text>
{lastLocation && (
<Text>
Last: {lastLocation.latitude}, {lastLocation.longitude}
</Text>
)}
{lastWarning && (
<Text style={{ color: 'orange' }}>
Warning: {lastWarning.message}
</Text>
)}
</View>
);
}

Throttled server sync

function ServerSyncTracker() {
const { locations } = useLocationUpdates({
onLocationUpdate: (location) => {
// This callback fires at most every 30 seconds
api.syncLocation(location);
},
onUpdateInterval: 30000, // 30 seconds
});

return <Text>{locations.length} locations recorded</Text>;
}

Notification action handling

function TrackingWithActions() {
const { isTracking } = useLocationUpdates({
onNotificationAction: (event) => {
switch (event.actionId) {
case 'pause':
// Handle pause action
break;
case 'stop':
stopTracking();
break;
}
},
});

return <Text>{isTracking ? 'Active' : 'Stopped'}</Text>;
}

Watching a specific trip

function TripViewer({ tripId }: { tripId: string }) {
const { locations, lastLocation, refreshLocations } = useLocationUpdates({
tripId,
autoLoad: true,
});

return (
<View>
<Text>Trip {tripId}: {locations.length} points</Text>
<Button title="Refresh" onPress={refreshLocations} />
</View>
);
}

All callbacks combined

function FullFeatureTracker() {
const {
locations,
lastLocation,
lastWarning,
isTracking,
error,
clearError,
clearLocations,
refreshLocations,
} = useLocationUpdates({
onLocationUpdate: (location) => {
console.log('Location:', location);
},
onLocationWarning: (warning) => {
if (warning.type === 'LOCATION_UNAVAILABLE') {
showAlert('GPS signal lost');
}
},
onNotificationAction: (event) => {
console.log('Action pressed:', event.actionId);
},
onUpdateInterval: 5000,
autoLoad: true,
});

// Component renders with all data available
}