React Native course ยท Module 7: Notifications
Project: Atlantis Notification System
Let's create a complete notification system!
import { useEffect, useRef, useState } from 'react';
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import { Platform } from 'react-native';
// Configuration
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowBanner: true,
shouldShowList: true,
shouldPlaySound: true,
shouldSetBadge: true,
}),
});
// Notifications hook
export function useNotifications() {
const [expoPushToken, setExpoPushToken] = useState<string>('');
const [notification, setNotification] = useState<Notifications.Notification>();
const notificationListener = useRef<Notifications.Subscription>();
const responseListener = useRef<Notifications.Subscription>();
useEffect(() => {
// Registration
registerForPushNotificationsAsync().then((token) => {
if (token) setExpoPushToken(token);
});
// Setup Android channels
setupAndroidChannels();
// Listeners
notificationListener.current = Notifications.addNotificationReceivedListener(
setNotification
);
responseListener.current = Notifications.addNotificationResponseReceivedListener(
(response) => {
handleNotificationResponse(response);
}
);
return () => {
notificationListener.current?.remove();
responseListener.current?.remove();
};
}, []);
return { expoPushToken, notification };
}
async function registerForPushNotificationsAsync() {
if (!Device.isDevice) {
console.log('Push notifications require a device');
return;
}
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
return;
}
const token = await Notifications.getExpoPushTokenAsync();
return token.data;
}
async function setupAndroidChannels() {
if (Platform.OS !== 'android') return;
await Notifications.setNotificationChannelAsync('default', {
name: 'Default',
importance: Notifications.AndroidImportance.MAX,
});
await Notifications.setNotificationChannelAsync('reminders', {
name: 'Reminders',
importance: Notifications.AndroidImportance.HIGH,
});
}
function handleNotificationResponse(response: Notifications.NotificationResponse) {
const data = response.notification.request.content.data;
// Navigate based on data
console.log('Notification data:', data);
}
// Notification services
export const NotificationService = {
// Local notification
sendLocal: async (title: string, body: string, data?: object) => {
return Notifications.scheduleNotificationAsync({
content: { title, body, data, sound: true },
trigger: null,
});
},
// Reminder
scheduleReminder: async (title: string, body: string, date: Date) => {
return Notifications.scheduleNotificationAsync({
content: { title, body },
trigger: date,
});
},
// Daily reminder
scheduleDailyReminder: async (title: string, body: string, hour: number, minute: number) => {
return Notifications.scheduleNotificationAsync({
content: { title, body },
trigger: { hour, minute, repeats: true },
});
},
// Cancel all
cancelAll: async () => {
await Notifications.cancelAllScheduledNotificationsAsync();
},
// Clear badge
clearBadge: async () => {
await Notifications.setBadgeCountAsync(0);
},
};This system handles registration, local notifications, push notifications, and Android channels!
Code for this lesson: App.tsx
import { View, Text, Button, StyleSheet } from 'react-native';
import * as Notifications from 'expo-notifications';
// Project: complete Atlantis notification service
export const NotificationService = {
// Immediate local notification
sendLocal: async (title: string, body: string, data?: object) => {
// TODO: call scheduleNotificationAsync with trigger: null
return Notifications.scheduleNotificationAsync({
content: { title, body, data, sound: true },
trigger: null,
});
},
// Reminder on a specific date
scheduleReminder: async (title: string, body: string, date: Date) => {
// TODO: set the trigger to the passed date
return Notifications.scheduleNotificationAsync({
content: { title, body },
trigger: date,
});
},
// Daily reminder at a given time
scheduleDailyReminder: async (title: string, body: string, hour: number, minute: number) => {
// TODO: set the trigger to { hour, minute, repeats: true }
return Notifications.scheduleNotificationAsync({
content: { title, body },
// TODO: complete the trigger with repeats: true
trigger: { hour, minute, repeats: false },
});
},
// Cancel all scheduled notifications
cancelAll: async () => {
// TODO: call cancelAllScheduledNotificationsAsync()
},
// Clear the app icon badge
clearBadge: async () => {
// TODO: set the badge to 0 with setBadgeCountAsync(0)
},
};
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.title}>Atlantis Notification System</Text>
<Button
title="Send local"
onPress={() => NotificationService.sendLocal('Atlantis', 'Poseidon summons you!')}
/>
<Button title="Clear badge" onPress={NotificationService.clearBadge} />
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#1a5276', gap: 16, padding: 20 },
title: { fontSize: 22, color: '#fff', textAlign: 'center' },
});
Docs entries used in this lesson
Spotted a mistake in this lesson?
Hands-on tasks in the game
- Code editor
Complete the code of the complete service.