React中为map渲染的Notification加key后setTimeout异常求助
通知组件key属性问题分析与解决
问题原因
- Key值选择错误:直接用
msg作为key时,若数组中出现重复消息、或消息内容重复,React会错误复用已有组件,而非创建新的Notification实例。 - 组件状态复用导致定时器同步:Notification的定时器仅在组件挂载时启动(
useEffect空依赖),若组件被复用,旧的定时器状态会被保留,新消息无法触发新定时器,最终所有通知同时消失。 - 数组更新逻辑冲突:若每次新增通知都保留所有历史消息,结合错误的key值,会导致旧组件被重新渲染但状态未重置,出现重复显示旧消息且同步消失的问题。
解决步骤
1. 给通知项添加唯一标识
将纯字符串数组改为带唯一ID的对象数组,确保每个通知实例有独立身份:
// 示例:父组件中存储通知的状态数组 const [notifications, setNotifications] = useState([ { id: Date.now(), msg: "第一条通知" }, // 新增时追加带唯一ID的对象(用时间戳或UUID生成id) ]);
2. 修正UseNotificationManager的key使用
使用通知项的唯一ID作为key,保证每个Notification组件独立挂载:
function UseNotificationManager(List, type) { return List.map((item) => { // 用唯一id作为key,避免组件复用 return <Notification key={item.id} type={type} msg={item.msg} />; }); }
3. 优化Notification组件定时器逻辑(可选)
若需要在消息内容更新时重置定时器,将msg加入useEffect依赖数组:
const Notification = (props) => { const [dNone, setdNone] = useState(false); useEffect(() => { const timeout = setTimeout(() => { setdNone(true); }, 4000); return () => clearTimeout(timeout); }, [props.msg]); // msg变化时重启定时器 return ( <div className={`custom-alert ${props.type} ${dNone ? "d-none" : ""}`}> <span className="bi bi-x-circle-fill error-icon-alert"></span> <div> <p className="mb-0 pb-0 custom-alert-desc">{props.msg}</p> </div> </div> ); };
4. 清理已消失的通知(可选)
避免数组堆积已失效的通知,在定时器触发时通知父组件移除对应项:
// Notification组件添加关闭回调 const Notification = (props) => { const [dNone, setdNone] = useState(false); useEffect(() => { const timeout = setTimeout(() => { setdNone(true); props.onClose?.(props.id); // 通知父组件移除该通知 }, 4000); return () => clearTimeout(timeout); }, [props.msg, props.id]); return ( <div className={`custom-alert ${props.type} ${dNone ? "d-none" : ""}`}> <span className="bi bi-x-circle-fill error-icon-alert"></span> <div> <p className="mb-0 pb-0 custom-alert-desc">{props.msg}</p> </div> </div> ); }; // 父组件处理移除逻辑 const handleClose = (id) => { setNotifications(prev => prev.filter(item => item.id !== id)); }; // 使用时传入回调 <Notification key={item.id} id={item.id} type={type} msg={item.msg} onClose={handleClose} />
效果验证
- 第一条通知挂载后,4秒后自动消失;
- 3秒后添加第二条通知,第一条会在第4秒消失,第二条在第7秒(3+4)消失;
- 新增通知仅创建新实例,不会复用旧组件,定时器各自独立运行。
内容的提问来源于stack exchange,提问作者yograj tandel
相关产品推荐
相关产品推荐

