You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS通知组件移除时下方组件继承fade属性问题修复咨询

修复NextJS+Tailwind通知组件的fade属性继承问题

问题描述:使用NextJS和Tailwind构建通知组件时,当展示多条通知,移除顶部通知后,下方的通知会意外继承被移除通知的fade属性,表现为下方通知突然消失(对应效果:顶部通知淡出后,后续通知直接消失而非正常显示)。

问题代码

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;

修复方案

问题根源在于列表渲染时使用了index作为key。当顶部通知被删除后,后续通知的index会向前偏移,React会复用之前的组件实例,导致旧组件的fade状态被错误继承。

只需要修改列表渲染的key值,将key={index}替换为key={notification.id}:

{notifications.map((notification) => {
    switch (notification.type) {
        case 'info':
            return <Info text={notification.text} key={notification.id} remove={() => removeNotification(notification.id)} fade={notification.fade} />
        /* other cases */
    }
})}

补充说明

  • 每个通知对象都有唯一的id(通过Math.random()生成),用它作为key可以确保React能准确识别每个列表项,不会因为列表项顺序变化而复用错误的组件实例。
  • 保持removeNotification逻辑不变,依然先标记fade为true,等待动画完成后再删除通知项,这样就能保证每个通知的淡出动画独立执行,不会影响其他通知。

内容的提问来源于stack exchange,提问作者AwiJol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:55:35