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

React组件出现Too many re-renders错误:点击通知展示详情功能的问题排查与解决

解决Too many re-renders错误与无限渲染问题

我来帮你排查并解决这个问题,咱们一步步拆解核心原因和修复方案:

1. 修复Notifications组件的useEffect异步写法错误

React的useEffect回调函数不能直接是async函数——因为async函数会返回Promise,而useEffect期望返回的是清理函数(function)或者undefined。这种写法会干扰React的状态更新逻辑,间接引发重渲染异常。

修复代码:

const Notification = (hospital) => { 
  const [users, setUsers] = useState([]); 
  const [search, setSearch] = useState(null); 
  const [status, setStatus] = useState(null); 
  const [notifDetails, setNotification] = useState(null); // 给初始值,避免undefined

  useEffect(() => {
    // 把异步逻辑包裹在内部函数中
    const fetchNotifications = async () => {
      try {
        const res = await axios.get("/notifications");
        const result = res.data;
        setUsers(result);
        // 加个判断,避免result为空时取result[0]报错
        if (result.length > 0) {
          setNotification(result[0]);
        }
      } catch (err) {
        console.error(err);
      }
    };
    fetchNotifications();
  }, []); 

  return( 
    {/* 用Fragment包裹多个顶级元素,React要求只能返回一个根元素 */}
    <>
      <div className="hospital-notif-container"> 
        {filteredList(users, status, search).map((details, index) => { 
          for (var i = 0; i < details.receiver.length; i++) { 
            if ( (details.receiver[i].id === hospital.PK || details.receiver[i].id === "others") && details.sender.id !== hospital.PK ) { 
              return ( 
                <div className="hospital-notif-row" key={index} onClick={() => setNotification(details)} > 
                  <div className="hospital-notif-row"> {details.name} </div> 
                </div> 
              ); 
            } 
          } 
          return null; 
        })} 
      </div> 
      <NotificationDetails details={notifDetails} /> 
    </>
  ); 
}

2. 修复NotificationDetails组件的空值处理逻辑

你的notifDetails初始值是undefined,导致NotificationDetails组件中执行Object.keys(details)时直接抛出Cannot convert undefined or null to object错误。这个错误会触发组件重新渲染,进而再次执行useEffect,形成无限循环。

修复代码:

const NotificationDetails = ({ details }) => { 
  const [loading, setLoading] = useState(true); 

  useEffect(() => {
    // 先判断details是否存在,再检查属性数量
    if (details && Object.keys(details).length !== 0) { 
      setLoading(false); 
    } else {
      // 当details为空时,重置loading状态
      setLoading(true);
    }
  }, [details]); 

  // 额外加一层判断,避免details为undefined时渲染报错
  if (!loading && details) { 
    return ( 
      <> 
        <div className="hospital-details-container"> 
          <h2>{details.sender.name}</h2> 
        </div> 
      </> 
    ); 
  } else {
    return (<div>Loading</div>);
  }
};

3. 优化:避免不必要的重渲染(可选)

如果filteredList是纯函数(输入相同则输出相同),可以用useMemo缓存其结果,避免每次组件渲染都重新生成数组,减少不必要的重渲染:

import { useMemo } from 'react';

// 在Notification组件内部添加
const filteredNotifications = useMemo(() => {
  return filteredList(users, status, search);
}, [users, status, search]); // 只有依赖项变化时才重新计算

// 替换原map中的filteredList调用
{filteredNotifications.map((details, index) => { 
  // 原循环逻辑不变
})}

关于“一直使用result[0]无限渲染”的解释

当你在Notifications组件的useEffect中设置setNotification(result[0])后,NotificationDetails的details属性更新,触发其useEffect执行setLoading(false)。但如果之前的空值处理错误没有修复,每次渲染都会抛出异常,React会尝试重新渲染组件,从而形成“无限渲染”的循环。修复上述问题后,这个循环就会被打破。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 23:18:12