skip to Main Content

I have a notification component that renders mui snackbar with alert. I want to show 3 notifications at a the same time under eachother. The problem is that when i try to close the second notification with clicking on the Close icon, it closes both (first and second). I mean each time it closes itself and the above one. What is the problem here?

type Props = {
  notifications: NotificationState[];
  removeNotification: (id: number) => void;
};

export function Notification({ notifications, removeNotification }: Props) {
  const [open, setOpen] = useState<{ [key: number]: boolean }>({});

  const handleClose = (id: number) => () => {
    setOpen((prevOpen) => ({
      ...prevOpen,
      [id]: false,
    }));
    removeNotification(id);
  };

  useEffect(() => {
    const updatedOpenMap: { [key: number]: boolean } = {};
    notifications.forEach((notification) => {
      updatedOpenMap[notification.id] = true;
    });
    setOpen(updatedOpenMap);
  }, [notifications]);

  return (
    <>
      {notifications.map((notification, index) => (
        <Snackbar
          key={notification.id}
          open={open[notification.id]}
          autoHideDuration={5000}
          anchorOrigin={{ vertical: "top", horizontal: "right" }}
          onClose={handleClose(notification.id)}
          style={{ marginTop: `${index * 60}px` }}
        >
          <div style={{ marginTop: "50px" }}>
            <Alert severity={notification.type} onClose={handleClose(notification.id)}>
              {notification.message}
            </Alert>
          </div>
        </Snackbar>
      ))}
    </>
  );
}
export default Notification;

2

Answers


  1. you are directly calling onClose={handleClose(notification.id)} which is most probably causing issue,
    do it like
    onClose{()=>handleClose(notification.id)}

    Login or Signup to reply.
  2. Your code has two issues, first of all you’re calling handleClose incorrectly, secondly the marginTop of Alert div parent is making interruption, try to remove it, this is the final code which works as you might expect:

    type Props = {
      notifications: NotificationState[];
      removeNotification: (id: number) => void;
    };
    
    export function Notification({ notifications, removeNotification }: Props) {
    
      const [open, setOpen] = useState<{ [key: number]: boolean }>({});
    
      const handleClose = (id: number) => () => {
        setOpen((prevOpen) => ({
          ...prevOpen,
          [id]: false
        }));
        removeNotification(id);
      };
    
      useEffect(() => {
        const updatedOpenMap: { [key: number]: boolean } = {};
        notifications.forEach((notification) => {
          updatedOpenMap[notification.id] = true;
        });
        setOpen(updatedOpenMap);
      }, [notifications]);
    
      return (
        <>
          {notifications.map((notification, index) => (
            <Snackbar
              key={notification.id}
              open={open[notification.id]}
              autoHideDuration={5000}
              anchorOrigin={{ vertical: "top", horizontal: "right" }}
              onClose={() => handleClose(notification.id)}
              style={{ marginTop: `${index * 60}px` }}
            >
              <Alert severity={notification.type as any} onClose={handleClose(notification.id)}>
                {notification.message}
              </Alert>
            </Snackbar>
          ))}
        </>
      );
    }
    
    export default Notification;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search