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

React实现Read More功能报错:过多重渲染,React限制渲染次数避免无限循环

问题修复方案

你代码的核心问题出在异步状态更新的时序错误、不符合React规范的状态使用方式,以及边界判断遗漏,具体修改如下:

首先修复App.js的冗余请求问题

你给Lists函数的useCallback依赖填了notifs,会导致每次通知列表更新后都重复请求接口,直接把依赖改为空数组即可,修改后代码:

import React, { useEffect, useState, useCallback } from 'react';
import Box from '@material-ui/core/Box';
import { notificationsApi } from './fakeAPI';
import ReadMore from './ReadMore';

const Notifications = () => {
  const [notifs, setNotifs] = useState(null);

  const Lists = useCallback(async () => {
    try {
      const notif = await notificationsApi.getNotifications();
      setNotifs(notif);
    } catch (e) {
      console.log(e);
    }
  }, []); // 依赖改为空数组,只在组件挂载时请求一次

  useEffect(() => {
    Lists();
  }, [Lists]);

  return (
    <Box>
      {notifs &&
        notifs.map((notif) => {
          return (
            <Box key={notif.id}>
              <ReadMore
                headerLimit={112}
                messageLimit={298}
                isRead={notif.isRead}
                headerNotif={notif.header}
                messageNotif={notif.message}
              />
            </Box>
          );
        })}
    </Box>
  );
};

export default Notifications;

然后重写ReadMore.js的逻辑

去掉存JSX到状态的写法,直接在渲染时计算显示内容,规避异步状态更新的时序问题,修改后代码:

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Box, Typography } from '@material-ui/core';

const ReadMore = (props) => {
  const { headerNotif, messageNotif, isRead, headerLimit, messageLimit } = props;
  const [isExpanded, setIsExpanded] = useState(false);
  
  // 直接计算要显示的头部内容
  const displayHeader = isExpanded 
    ? headerNotif 
    : headerNotif.length > headerLimit 
      ? `${headerNotif.substr(0, headerLimit)}...` 
      : headerNotif;
  
  // 直接计算要显示的消息内容
  const displayMessage = isExpanded 
    ? messageNotif 
    : messageNotif.length > messageLimit 
      ? `${messageNotif.substr(0, messageLimit)}...` 
      : messageNotif;
  
  // 判断是否需要显示展开/收起按钮
  const showToggle = headerNotif.length > headerLimit || messageNotif.length > messageLimit;

  return (
    <span>
      <Box sx={{ pb: 1 }}>
        <Typography
          variant="subtitle2"
          style={{
            fontSize: 16,
            color: isRead ? '#333333' : '#008C44',
          }}
        >
          {displayHeader}
        </Typography>
      </Box>
      <Box sx={{ pb: 1 }}>
        <Typography
          variant="body2"
          style={{
            fontSize: 12,
            color: '#666666',
          }}
        >
          {displayMessage}
        </Typography>
      </Box>

      {showToggle && (
        <span
          style={{
            color: '#008C44',
            cursor: 'pointer',
            display: 'block',
            fontSize: 14,
            paddingTop: isExpanded ? 0 : 2
          }}
          onClick={() => setIsExpanded(!isExpanded)}
        >
          <u>{isExpanded ? ' View Less' : ' View More'}</u>
        </span>
      )}
    </span>
  );
};

ReadMore.propTypes = {
  headerLimit: PropTypes.number,
  messageLimit: PropTypes.number,
  headerNotif: PropTypes.string.isRequired,
  messageNotif: PropTypes.string.isRequired,
  isRead: PropTypes.bool.isRequired
};

export default ReadMore;

优化说明

  • 去掉了所有存储JSX的冗余状态,只用一个isExpanded状态控制展开收起,逻辑更简洁,不会出现异步更新的时序问题
  • 修复了原代码里长度等于限制值时的边界判断遗漏问题
  • 补全了PropTypes的必填项校验,避免后续参数传错的问题
  • 去掉了不必要的状态和函数调用,渲染性能更好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 07:06:03