import { useEffect, useCallback } from 'react';
import { useIntl } from 'react-intl';
import { useDispatch, useSelector } from 'react-redux';
import { useSnackbar } from 'notistack';
import { removeSnackbar } from '../redux/notifier/slice';
let displayed = [];
const useNotifier = () => {
const intl = useIntl();
const dispatch = useDispatch();
const notifications = useSelector((state) => state.notifier);
console.log('notifications', notifications);
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
const storeDisplayed = (id) => {
displayed = [...displayed, id];
};
const removeDisplayed = (id) => {
displayed = [...displayed.filter((key) => id !== key)];
};
const showNotification = useCallback(
(
key,
message,
options = {},
values = {},
) => {
enqueueSnackbar(
intl.formatMessage(
{
id: message,
defaultMessage: 'Something went wrong',
},
values
),
{
key,
...options,
onClose: (event, reason, key) => {
if (options.onClose) {
options.onClose(event, reason, key);
}
},
onExited: (event, key) => {
dispatch(removeSnackbar({ key }));
removeDisplayed(key);
},
}
);
},
[dispatch, enqueueSnackbar, intl]
);
const closeNotification = useCallback(
(key) => {
closeSnackbar(key);
},
[closeSnackbar]
);
useEffect(() => {
notifications.forEach(({ key, message, options, dismissed=false, values }) => {
if (dismissed) {
closeNotification(key);
return;
}
if (displayed.includes(key)) return;
showNotification(key, message, options, values);
storeDisplayed(key);
});
}, [notifications, showNotification, closeNotification]);
};
export default useNotifier;
I am using to following custom hook to display snackbar notification with the notistack library but the snackbar keeps re-rendering indefinitely
My notifier slice looks like the following
import { createSlice } from '@reduxjs/toolkit';
const notifierSlice = createSlice({
name: 'notifier',
initialState: [],
reducers: {
enqueueSnackbar: (state, action) => {
const key = action.payload.options && action.payload.options.key;
state.push({
key: key || new Date().getTime() + Math.random(),
...action.payload,
});
},
closeSnackbar: (state, action) => {
return state.map((notification) => (
(action.dismissAll || notification.key === action.key)
? { ...notification, dismissed: true }
: { ...notification }
));
},
removeSnackbar: (state, action) => {
return state.filter(
(notification) => notification.key !== action.key,
);
},
},
});
export const {
enqueueSnackbar,
closeSnackbar,
removeSnackbar
} = notifierSlice.actions;
export default notifierSlice.reducer;
Any idea how to modify the code to stop it from re-rendering when the notification is displayed. Thanks for your help
The issue you're facing is due to how you're updating and managing the displayed array in your useNotifier hook. Here's the updated code ,try this :
In the above code I removed the separate functions (storeDisplayed and removeDisplayed) that manage the displayed array. Instead, the logic for displaying notifications is simplified by directly calling enqueueSnackbar in the useEffect based on the notifications received from Redux.