React Native SDK Examples
Real-world examples using de.sdk-rn based on actual implementation.
Example Apps
Complete examples showing:
- Basic Map Integration - Rendering MSI component
- Live Location Tracking - Using handles.myLocation()
- Peer Tracking - Driver/agent location updates
- Fleet Management - Multiple entity tracking
- Navigation - Turn-by-turn routing
- Order Management - Using DClient
Complete App Example
Full implementation from real codebase.
App Structure
typescript
// App.tsx
import { Stack } from 'expo-router'
import { View, StyleSheet, ActivityIndicator, TouchableOpacity, AppState } from 'react-native'
import React, { useRef, useEffect, useState } from 'react'
import { Auth, MSI, Utils, type MSIRef, type MSIInterface } from '@de./sdk-rn'
const credentials = {
remoteOrigin: 'https://your-app.com',
context: 'your-context-token',
cid: 'your-connector-id',
secret: 'your-connector-secret'
}
// Create Auth instance with autorefresh
const auth = new Auth(credentials, {
env: 'prod',
autorefresh: true
})
export default function Index() {
const msiRef = useRef<MSIRef>(null)
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [isReady, setIsReady] = useState(false)
const hasInitializedRef = useRef(false)
// Fetch token on mount
useEffect(() => {
async function initialize() {
try {
const token = await auth.getToken()
if (!token) {
setError('Failed to get access token')
setIsLoading(false)
return
}
setError(null)
} catch (err) {
setError(err instanceof Error ? err.message : 'Authentication failed')
} finally {
setIsLoading(false)
}
}
initialize()
return () => {
console.log('[MSI] Component unmounting, stopping auto-refresh')
auth.stopAutoRefresh()
}
}, [])
// Handle MSI loaded
const handleLoaded = async ({ handles, controls }: MSIInterface) => {
if (hasInitializedRef.current) {
console.log('[MSI] Already initialized, skipping')
return
}
console.log('[MSI] Loaded - initializing')
hasInitializedRef.current = true
try {
// Your app logic here
await initializeMap({ handles, controls })
} catch (error) {
console.error('[MSI] Error:', error)
setError(error instanceof Error ? error.message : 'Initialization failed')
}
}
const handleRetry = () => {
setError(null)
hasInitializedRef.current = false
setIsReady(false)
msiRef.current?.retry()
}
if (isLoading) {
return (
<View style={styles.center}>
<ActivityIndicator size="large" />
</View>
)
}
if (error) {
return (
<View style={styles.center}>
<Text style={styles.error}>{error}</Text>
<TouchableOpacity onPress={handleRetry}>
<Text>Retry</Text>
</TouchableOpacity>
</View>
)
}
return (
<View style={styles.container}>
<MSI
ref={msiRef}
env="prod"
getAccessToken={() => auth.accessToken || ''}
onReady={() => setIsReady(true)}
onLoaded={handleLoaded}
onError={(error) => setError(error.message)}
/>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1 },
center: { flex: 1, justifyContent: 'center', alignItems: 'center' },
error: { color: 'red', marginBottom: 16 }
})Example 1: Basic Route Display
Create and display a route on the map.
typescript
async function initializeMap({ controls }: MSIInterface) {
// Pin current location
const currentLocation = await controls.pinCurrentLocation()
console.log('Current location:', currentLocation)
// Set route
await controls.setRoute({
routeId: 'delivery-1',
origin: {
coords: { lng: -0.1173, lat: 5.6413 },
caption: { label: 'Pickup' }
},
destination: {
coords: { lng: -0.1247, lat: 5.6209 },
caption: { label: 'Delivery' }
},
options: {
profile: 'driving-traffic',
animation: 'dot:flow',
pointless: true // Hide waypoint markers
}
})
// Fit route in view
await controls.fitRoutesBounds({ margin: 100 })
}Example 2: Live Location Tracking
Track user's live location using handles.
typescript
function setupLiveLocation(handles: MSIInterface['handles']) {
const stream = handles.myLocation('client')
if (!stream) {
console.error('Failed to create location stream')
return
}
stream
.on('data', (location) => {
console.log('Live location:', location)
// Send to backend
sendLocationUpdate(location)
})
.onerror((error) => {
console.error('Location error:', error)
})
.onclose(() => {
console.log('Location stream closed')
})
// Return cleanup function
return () => stream.close()
}Example 3: Peer Location Tracking
Track driver/agent location with real-time updates.
typescript
function trackDriverLocation(
handles: MSIInterface['handles'],
initialPosition: { lng: number, lat: number, heading: number }
) {
// Create peer stream
const peerStream = handles.peerLocation(initialPosition, {
label: 'Driver',
duration: 5,
unit: 'min'
})
if (!peerStream) return
// Create live stream for updates
const liveStream = new Utils.Stream()
// Listen to WebSocket for driver updates
const ws = new WebSocket('wss://api.dedot.io')
ws.onmessage = (event) => {
const data = JSON.parse(event.data)
if (data.type === 'driver:location') {
liveStream.sync({
position: {
lng: data.location.lng,
lat: data.location.lat,
heading: data.bearing
},
caption: {
duration: data.eta,
unit: 'min',
label: 'Driver arriving'
}
})
}
}
// Pipe updates to peer stream
liveStream.pipe(peerStream)
// Cleanup
return () => {
ws.close()
liveStream.close()
}
}Example 4: Fleet Management
Track multiple vehicles using nearby handles.
typescript
function setupFleetTracking(
handles: MSIInterface['handles'],
vehicles: Array<{
id: string
location: { lng: number, lat: number, heading: number }
}>
) {
const entities = vehicles.map(v => ({
id: v.id,
status: 'ACTIVE' as const,
grade: '1H' as const,
type: 'car' as const,
currentLocation: v.location
}))
const nearbyStream = handles.nearby(entities)
if (!nearbyStream) return
const liveStream = new Utils.Stream()
// Setup live controls
nearbyStream
.live(async (controls) => {
// Add new vehicle
await controls.add({
id: 'new-vehicle',
status: 'ACTIVE',
grade: '1H',
type: 'car',
currentLocation: {
lng: -0.1801,
lat: 5.6853,
heading: 90
}
})
// Move existing vehicle
const moving = setInterval(async () => {
await controls.move({
id: vehicles[0].id,
position: {
lng: vehicles[0].location.lng += 0.0001,
lat: vehicles[0].location.lat += 0.0001,
heading: 45
}
})
}, 1000)
// Remove vehicle after 10 seconds
setTimeout(async () => {
await controls.remove('new-vehicle')
clearInterval(moving)
}, 10000)
})
.pipe(liveStream)
// Cleanup
return () => {
nearbyStream.close()
liveStream.close()
}
}Example 5: Turn-by-Turn Navigation
Implement navigation with real-time position updates.
typescript
async function startNavigation(
handles: MSIInterface['handles'],
journey: {
routeId: string
origin: { lng: number, lat: number }
destination: { lng: number, lat: number }
waypoints?: Array<{ lng: number, lat: number }>
}
) {
const navStream = await handles.navigation({
routeId: journey.routeId,
origin: {
coords: journey.origin,
caption: { label: 'Start' }
},
destination: {
coords: journey.destination,
caption: { label: 'End' }
},
waypoints: journey.waypoints?.map(w => ({
coords: w,
caption: { label: 'Stop' }
})),
options: {
profile: 'driving-traffic',
mode: 'navigation'
}
})
if (!navStream) {
throw new Error('Failed to create navigation stream')
}
const liveStream = new Utils.Stream()
// Track user position with GPS
const watchId = navigator.geolocation.watchPosition(
(position) => {
liveStream.sync({
position: {
lng: position.coords.longitude,
lat: position.coords.latitude,
heading: position.coords.heading || 0
}
})
},
(error) => console.error('GPS error:', error),
{
enableHighAccuracy: true,
distanceFilter: 10,
interval: 2000
}
)
// Pipe position updates to navigation
liveStream.pipe(navStream)
// Listen to navigation events
navStream
.on('data', (data) => {
console.log('Navigation update:', data)
})
.onerror((error) => {
console.error('Navigation error:', error)
})
// Cleanup
return () => {
navigator.geolocation.clearWatch(watchId)
liveStream.close()
}
}Example 6: Order Management
Create and manage orders using DClient.
typescript
import { DClient, Auth } from '@de./sdk-rn'
const auth = new Auth(credentials, { env: 'prod', autorefresh: true })
const orderClient = new DClient.Order({
context: credentials.context,
getAccessToken: () => auth.accessToken || ''
})
async function createDeliveryOrder(
pickup: { address: string, coords: { lng: number, lat: number } },
delivery: { address: string, coords: { lng: number, lat: number } },
customerId: string
) {
try {
// Generate intent token
const intentToken = await orderClient.intent(customerId)
// Add waypoints
const waypoints = await orderClient.addWaypoint([
{
no: 1,
type: 'pickup',
description: pickup.address,
coordinates: pickup.coords,
contact: {
type: 'business',
reference: 'restaurant-1',
phone: '+1234567890'
}
},
{
no: 2,
type: 'dropoff',
description: delivery.address,
coordinates: delivery.coords,
contact: {
type: 'client',
reference: customerId,
phone: '+0987654321'
}
}
], intentToken)
// Add package details
await orderClient.addPackage({
waypointNo: 1,
careLevel: 2,
category: 'food',
weight: 2.5,
note: 'Handle with care'
}, intentToken)
// Set service options
await orderClient.setService({
'fees.total.amount': 15.99,
'fees.total.currency': 'USD',
'payment.mode': 'card',
'payment.paid': true,
xpress: 'standard'
}, intentToken)
// Update stage
await orderClient.updateStage('assigned', intentToken)
return { intentToken, waypoints }
} catch (error) {
console.error('Order creation failed:', error)
throw error
}
}Example 7: Search and Geocoding
Search for places and geocode addresses.
typescript
async function searchAndSelect(controls: MSIInterface['controls']) {
// Search for place
const suggestions = await controls.searchQuery(
'Accra Mall',
{ lng: -0.1769, lat: 5.6037 } // Near this location
)
console.log('Suggestions:', suggestions)
// [{ id, name, description, distance }, ...]
// Select first result
const selected = await controls.searchSelect(0)
console.log('Selected place:', selected)
// { name, location: { lng, lat }, address }
// Resolve address to coordinates
const coords = await controls.resolvePlace('Madina, Accra, Ghana')
console.log('Coordinates:', coords)
// Reverse geocode coordinates
const place = await controls.resolveCoordinates('-0.176,5.683')
console.log('Place:', place)
}Example 8: Interactive Location Picker
Let user pick location by dragging.
typescript
async function pickLocation(
controls: MSIInterface['controls'],
handles: MSIInterface['handles']
) {
// Enable drag-pick mode
await controls.enableDragPickLocation({
lng: -0.1769,
lat: 5.6037
})
// Update content during drag
await controls.setDragPickContent('duration', {
time: 5,
unit: 'min'
})
// Listen for user pick
handles.onPickLocation((location) => {
console.log('User picked:', location)
// { point: { x, y }, coordinates: { lng, lat } }
// Disable picker
controls.disableDragPickLocation()
// Use the picked location
saveLocation(location.coordinates)
})
}Complete Delivery App
Full app combining all features.
typescript
function DeliveryApp() {
const msiRef = useRef<MSIRef>(null)
const [order, setOrder] = useState(null)
const handleLoaded = async ({ controls, handles }: MSIInterface) => {
// 1. Get current location
const location = await controls.pinCurrentLocation()
// 2. Create order
const orderData = await createDeliveryOrder(
{ address: 'Restaurant', coords: { lng: -0.1173, lat: 5.6413 } },
{ address: 'Customer', coords: location! },
'customer-123'
)
setOrder(orderData)
// 3. Set route
await controls.setRoute({
routeId: orderData.intentToken,
origin: { coords: { lng: -0.1173, lat: 5.6413 } },
destination: { coords: location! },
options: { profile: 'driving-traffic', animation: 'dot:flow' }
})
// 4. Track driver
const cleanup = trackDriverLocation(handles, {
lng: -0.1173,
lat: 5.6413,
heading: 0
})
// 5. Setup live location
const cleanupLocation = setupLiveLocation(handles)
return () => {
cleanup?.()
cleanupLocation?.()
}
}
return (
<MSI
ref={msiRef}
env="prod"
getAccessToken={() => auth.accessToken || ''}
onLoaded={handleLoaded}
/>
)
}Best Practices
Do
- Use Auth with autorefresh enabled
- Clean up streams when unmounting
- Handle errors gracefully
- Use refs for MSI component
- Store credentials securely
- Test on real devices
Avoid
- Hardcoding credentials
- Creating multiple MSI instances
- Forgetting stream cleanup
- Ignoring error callbacks
- Testing only on simulators
- Blocking the main thread

