React Hot Toast

Current favorite lib for toast notifications, with some custom hook and implementation

––– views

React Hot Toast

A lib for toast notifications, my current favorite. Checkout the documentation

Package Dependencies

yarn add react-hot-toast
bash

Set up

Add the div to _app.js or App.jsx

import { Toaster } from 'react-hot-toast';
function MyApp({ Component, pageProps }) {
return (
<>
<div>
<Toaster
reverseOrder={false}
position='bottom-right'
toastOptions={{
style: {
borderRadius: '8px',
background: '#333',
color: '#fff',
},
}}
/>
</div>
<Component {...pageProps} />
</>
);
}
jsx

Usage

import toast from 'react-hot-toast';
function addSomething() {
toast.success('message');
toast.error('message');
}
jsx

Toast Promise Example

With promise, we don't need to use toast.success or toast.error, but directly send a promise, and it will be managed.

toast.promise(
axios
.post('/user/login', data)
.then((res) => {
const { jwt: token } = res.data.data;
tempToken = token;
localStorage.setItem('token', token);
// chaining axios in 1 promise
return axios.get('/user/get-user-info');
})
.then((user) => {
const role = user.data.data.user_role;
dispatch('LOGIN', { ...user.data.data, token: tempToken });
history.replace('/');
}),
{
loading: 'Loading...',
success: 'Success',
error: (err) => err.response.data.msg,
}
);
jsx

useLoadingToast hook

Using a useLoadingToast hook we can get access if there is any loading toast showing, then use it to disable button.

import { useToasterStore } from 'react-hot-toast';
export default function useLoadingToast() {
const { toasts } = useToasterStore();
const isLoading = toasts.some((toast) => toast.type === 'loading');
return isLoading;
}
jsx

useSWRLoadingToast hook

This hook will handle loading and error state from SWR and show toast on initial fetch. Revalidating will not trigger loading toast.

import { useEffect, useState } from 'react';
import toast from 'react-hot-toast';
export default function useSWRLoadingToast(data, error, customMessages = {}) {
const [toastId, setToastId] = useState(data ? 'done' : 'idle');
const toastMessage = {
loading: 'Loading...',
success: 'Success',
error:
error?.response?.data?.msg ?? 'Something is wrong, please try again.',
...customMessages,
};
useEffect(() => {
// if toastId is done,
// then it is not the first render or the data is already cached
if (toastId === 'done') return;
if (error) {
toast.error(toastMessage.error, { id: toastId });
setToastId('done');
} else if (data) {
toast.success(toastMessage.success, { id: toastId });
setToastId('done');
} else {
setToastId(toast.loading(toastMessage.loading));
}
return () => {
toast.dismiss();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data, error]);
}
jsx