useNotifications
Location: src/hooks/useNotifications.js
Overview
Provides comprehensive notification management for the current user. Fetches notifications from the notifications table, subscribes to real-time updates (INSERT and UPDATE), and supports marking individual, multiple, or all notifications as read, as well as deleting notifications. All mutations use optimistic updates with rollback on error.
Signature
function useNotifications(userId: string): {
// State
notifications: Notification[],
unreadCount: number,
isLoading: boolean,
error: string | null,
// Actions
markAsRead: (notificationId: string) => Promise<void>,
markMultipleAsRead: (notificationIds: string[]) => Promise<void>,
markAllAsRead: () => Promise<void>,
deleteNotification: (notificationId: string) => Promise<void>,
refresh: () => void,
fetchNotifications: (limit?: number) => Promise<void>,
fetchUnreadCount: () => Promise<void>,
clearError: () => void
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | The current user's ID |
Return Value
| Property | Type | Description |
|---|---|---|
notifications | Notification[] | Array of notification objects, ordered by created_at descending |
unreadCount | number | Number of unread notifications |
isLoading | boolean | Whether notifications are being fetched |
error | string | null | Error message if fetching or mutations failed |
markAsRead | (notificationId) => Promise<void> | Mark a single notification as read (optimistic update) |
markMultipleAsRead | (notificationIds) => Promise<void> | Mark multiple notifications as read via mark_notifications_read RPC |
markAllAsRead | () => Promise<void> | Mark all notifications as read via mark_all_notifications_read RPC |
deleteNotification | (notificationId) => Promise<void> | Delete a notification (optimistic update with rollback) |
refresh | () => void | Re-fetch all notifications |
fetchNotifications | (limit?) => Promise<void> | Fetch notifications with an optional limit (default 50) |
fetchUnreadCount | () => Promise<void> | Fetch only the unread count via get_unread_notification_count RPC |
clearError | () => void | Clear the error state |
Usage
import { useNotifications } from '../hooks/useNotifications';
function NotificationsPanel({ userId }) {
const {
notifications,
unreadCount,
isLoading,
markAsRead,
markAllAsRead,
deleteNotification
} = useNotifications(userId);
if (isLoading) return <Skeleton />;
return (
<div>
<header>
<h2>Notifications ({unreadCount} unread)</h2>
<button onClick={markAllAsRead}>Mark all read</button>
</header>
{notifications.map(n => (
<NotificationItem
key={n.id}
notification={n}
onRead={() => markAsRead(n.id)}
onDelete={() => deleteNotification(n.id)}
/>
))}
</div>
);
}
Notes
- Real-time subscriptions listen for both
INSERT(new notifications) andUPDATE(read status changes) events. - All write operations use optimistic updates and revert on error.
- The Supabase channel is cleaned up on unmount to prevent memory leaks.
Last updated: 2026-02-07