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

React中为map渲染的Notification加key后setTimeout异常求助

通知组件key属性问题分析与解决

问题原因

  1. Key值选择错误:直接用msg作为key时,若数组中出现重复消息、或消息内容重复,React会错误复用已有组件,而非创建新的Notification实例。
  2. 组件状态复用导致定时器同步:Notification的定时器仅在组件挂载时启动(useEffect空依赖),若组件被复用,旧的定时器状态会被保留,新消息无法触发新定时器,最终所有通知同时消失。
  3. 数组更新逻辑冲突:若每次新增通知都保留所有历史消息,结合错误的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 10:02:48