Skip to main content

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
})
}

ParameterDescription
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>): numberBy 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>): booleanKeep the toast that meets the condition specified in the callback function.
info

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>
)
}
tip

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>
)
}
info

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 and read
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>
)
}