useNotificationCenter
useNotificationCenter
is a headless hook to build your notification center on top of react-toastify. In short, every time you call toast
or any other variants like toast.update
, toast.promise
, toast.info
, etc, the notification will be added to the toast center.
It offers a lot of flexibility out of the box like sorting
, filtering
, etc...
Check the example below.
Import
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
Initial parameters
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
interface Data {
exclude: boolean
}
function App(){
const { notifications } = useNotificationCenter<Data>({
data: [
{id: "anId", createdAt: Date.now(), data: { exclude: false }},
{id: "anotherId", createdAt: Date.now(), data: { exclude: true }}
],
sort: (l, r) => l.createdAt - r.createdAt,
filter: (item) => item.data.exclude === false
})
}
Parameter | Description |
---|---|
data?: NotificationCenterItem<Data>[] | Initial data to rehydrate the notification center. Useful if you want to persist the content of the notification center |
sort?: (l: NotificationCenterItem<Data>, r: NotificationCenterItem<Data>): number | By default, the notifications are sorted from the newest to the oldest using the createdAt field. Use this to provide your sort function |
filter?: (item: NotificationCenterItem<Data>): boolean | Keep the toast that meets the condition specified in the callback function. |
All parameters are optional
API
The hook gives you access to several values and functions. Let's view them one by one.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
const {
notifications,
clear,
markAllAsRead,
markAsRead,
add,
update,
remove,
find,
sort,
unreadCount
} = useNotificationCenter()
notifications
Contains an array of NotificationItem
. The NotificationItem
has the following interface
interface NotificationCenter <Data = {}> {
id: Id
read: boolean;
createdAt: number;
data: Data;
content?: React.ReactNode
theme?: Theme
type?: TypeOptions;
isLoading?: boolean;
containerId?: Id;
icon?: React.ReactNode | false;
}
Most of the properties are populated when you display a notification on the screen using the toast
function. A typical usage would look like this.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
function App(){
const { notifications } = useNotificationCenter()
return (
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>id: {notification.id}</span>
<span>createdAt: {notification.createdAt}</span>
<p>content: {notification.content}</p>
{/* you get the idea, you are free to use the properties the way that best suits your needs */}
</li>
))}
</ul>
)
}
The content
contains the value that is displayed when calling the toast function. Use data
if you want more control.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
interface Data {
title: string
text: string
}
// somewhere in your app
toast("Hello", {
data: {
title: "Hello",
text: "Lorem ipsum dolor..."
}
})
function App(){
const { notifications } = useNotificationCenter<Data>()
return (
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>id: {notification.id}</span>
<span>createdAt: {notification.createdAt}</span>
<p>title: {notification.data.title}</p>
<p>text: {notification.data.text}</p>
</li>
))}
</ul>
)
}
clear
Remove all notifications from the notification center.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
function App(){
const { notifications, clear } = useNotificationCenter()
return (
<div>
<button onClick={clear}>clear</button>
<div>{notifications.length}</div>
</div>
)
}
markAllAsRead
Mark all notifications as read.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
function App(){
const { notifications, markAllAsRead } = useNotificationCenter()
return (
<div>
<button onClick={markAllAsRead}>Mark all as read</button>
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>read: {notification.read}</span>
</li>
))}
</ul>
</div>
)
}
markAllAsRead
accepts an optional boolean argument. It's only useful to mark all notifications as not read.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
function App(){
const { notifications, markAllAsRead } = useNotificationCenter()
return (
<div>
<button onClick={() => markAllAsRead(false)}>Mark all as not read</button>
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>read: {notification.read}</span>
</li>
))}
</ul>
</div>
)
}
Calling markAllasRead()
is equivalent to markAllAsRead(true)
// function signature
markAllAsRead(read?: boolean): void
markAsRead
Mark one or more notifications as read.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
function App(){
const { notifications, markAsRead } = useNotificationCenter()
return (
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>read: {notification.read}</span>
<button onClick={() => markAsRead(notification.id)}>mark as read</button>
</li>
))}
</ul>
)
}
You can also provide an array of ids to mark multiple notifications as read.
markAsRead(["a","list", "of", "id"])
Similar to markAllAsRead
, this function accepts an optional boolean argument. It's only useful to mark the notifications as not read.
markAsRead(notification.id, false)
// works for an array of ids as well
markAsRead(["a","list", "of", "id"], false)
unreadCount
Contains the number of unread notifications.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
function App(){
const { unreadCount } = useNotificationCenter()
return (
<div>{unreadCount}</div>
)
}
remove
Remove one or more notifications.
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
function App(){
const { notifications, remove } = useNotificationCenter()
return (
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<button onClick={() => remove(notification.id)}>remove</button>
</li>
))}
</ul>
)
}
To remove multiple notifications at once, you can pass an array of ids.
remove(["a","list", "of", "id"])
sort
By default, the notifications are sorted from the newest to the oldest using the createdAt
field. This can be changed anytime and you are free to use whatever field you want.
import { useNotificationCenter, NotificationCenterItem } from "react-toastify/addons/useNotificationCenter"
function App(){
const { notifications, sort } = useNotificationCenter()
const sortAsc = () => {
sort((l: NotificationCenterItem, r: NotificationCenterItem) => l.createdAt - r.createdAt)
}
return (
<div>
<button onClick={sortAsc}>Oldest to newest</button>
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>{notification.id}</span>
</li>
))}
</ul>
</div>
)
}
Another example, using a field different from createdAt
. We can imagine that the notification contains an order
field under data
.
// somewhere in your app
toast("hello", {
data: {
order: 1
}
})
import { useNotificationCenter, NotificationCenterItem } from "react-toastify/addons/useNotificationCenter"
interface Data {
order: number
}
function App(){
const { notifications, sort } = useNotificationCenter<Data>()
const sortAsc = () => {
sort((l: NotificationCenterItem, r: NotificationCenterItem) => l.data.order - r.data.order)
}
return (
<div>
<button onClick={sortAsc}>Oldest to newest</button>
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>{notification.id}</span>
</li>
))}
</ul>
</div>
)
}
add
Let you add a notification without calling toast
. This can be useful in many cases, job listener, global store, etc...
import { useEffect } from "react"
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
import { jobListener } from "my-job-listener"
function App(){
const { notifications, add } = useNotificationCenter()
useEffect(() => {
const unsub = jobListener.on("jobCreate",(job) => {
add({ id: job.id, content: job.notification.content })
})
// although the reference of `add` changes for every render
// you can safely omit it from the dependency array
}, [])
return (
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>{notification.id}</span>
</li>
))}
</ul>
)
}
- If the id is already in use, the function will return
null
and nothing will happens.
add({ id: "an existing id" }) // return null
- If you omit the
id
, one is generated for you.
add({ content: "hello" }) // return generated id
- You can also override the default values for
createdAt
andread
add({
// same as default value 😆
createdAt: Date.now(),
read: true
})
update
Let you update a notification without calling toast.update
. This can be useful in many cases, job listener, global store, etc...
import { useEffect } from "react"
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
import { jobListener } from "my-job-listener"
function App(){
const { notifications, update } = useNotificationCenter()
useEffect(() => {
const unsub = jobListener.on("jobUpdate", (job) => {
update(job.id, { content: job.notification.content, data: { jobType: job.type } })
})
// although the reference of `update` changes for every render
// you can safely omit it from the dependency array
}, [])
return (
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>{notification.id}</span>
</li>
))}
</ul>
)
}
- if the given id does not exist, null is returned
update("nonExistingId", {content: "hello"}) // return null
find
Let you retrieve one or more notifications. This can be useful in many cases, job listener, global store, etc...
import { useEffect } from "react"
import { useNotificationCenter } from "react-toastify/addons/useNotificationCenter"
import { jobListener } from "my-job-listener"
function App(){
const { notifications, find } = useNotificationCenter()
useEffect(() => {
const unsub = jobListener.onChange((job) => {
const notification = find(job.id);
if(notification) {
// do something if it already exist, for example update it
} else {
// do something if it does not exist, for example add it
}
})
// although the reference of `find` changes for every render
// you can safely omit it from the dependency array
}, [])
return (
<ul>
{notifications.map(notification => (
<li key={notification.id}>
<span>{notification.id}</span>
</li>
))}
</ul>
)
}