0

So I'm using NextJS and tailwind to create a notification provider for my app, however when I display multiple notifications and the top one gets removed the one underneath it takes over it's fade value, how do I fix this? enter image description here

import { createContext, useState, useContext } from "react";

const Context = createContext();

const Provider = ({ children }) => {
    const [notifications, setNotifications] = useState([]);

    const exposed = {
        addNotification: (type, text, autoClose) => {
            const id = Math.random()
            setNotifications(notifications => [...notifications, { id, type, text, autoClose, fade: false }]);
            if (autoClose) {
                setTimeout(() => {
                    removeNotification(id);
                }, 5000);
            }
        },
    };

    const removeNotification = (id) => {
        setNotifications(notifications => notifications.map(n => n.id === id ? { ...n, fade: true } : n));
        setTimeout(() => {
            setNotifications(notifications => notifications.filter(n => n.id !== id));
        }, 1000);
    }

    return (
        <Context.Provider value={exposed}>
            {children}
            {notifications.length > 0 ? <div className="z-50 fixed top-5 right-5 text-right">
                {notifications.map((notification, index) => {
                    switch (notification.type) {
                        case 'info':
                            return <Info text={notification.text} key={index} remove={() => removeNotification(notification.id)} fade={notification.fade} />
                        /* other cases */
                    }
                })}
            </div> : null}
        </Context.Provider>
    );
}

function Info({ remove, text, fade }) {
    return (
        <div className={`flex items-center w-fit mt-2 mr-0 ml-auto transition-opacity ease-in duration-1000 ${!fade?'opacity-100':'opacity-0'}`}>
            {/* content */}
        </div>
    )
}

export const useProvider = () => useContext(Context);

export default Provider;
AwiJol
  • 27
  • 1
  • 1
  • 4

1 Answers1

0

There might be other issues to be addressed, but for a list with dynamically changing items, consider to avoid using index as unique key to prevent potential conflicts when the list changes.

Perhaps try use notification.id as key in the posted example:

<Context.Provider value={exposed}>
  {children}
  {notifications.length > 0 ? (
    <div className="z-50 fixed top-5 right-5 text-right">
      {notifications.map((notification, index) => {
        switch (notification.type) {
          case "info":
            return (
              <Info
                text={notification.text}
                //  Use id as unique keys
                key={notification.id}
                remove={() => removeNotification(notification.id)}
                fade={notification.fade}
              />
            );
          /* other cases */
        }
      })}
    </div>
  ) : null}
</Context.Provider>
John Li
  • 6,976
  • 3
  • 3
  • 27
  • 1
    Thanks, I changed it, and it also fixed my issue, I'll avoid using index next time. Are there any other reasons to do so? – AwiJol Jan 30 '23 at 20:48
  • 1
    @AwiJol Thanks for the reply, I think this [answer](https://stackoverflow.com/a/43892905/20436957) explains how to use unique keys with great details and can be referenced. – John Li Jan 30 '23 at 20:53