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

React在useEffect中设置state触发Maximum update depth exceeded错误如何解决

问题原因及解决方案

死循环触发原因

你的代码产生无限重渲染的核心原因是 useEffect的依赖项和内部更新逻辑形成了闭环:
以处理来电数据的useEffect为例,你把incomingCalls放到了依赖列表中,同时effect内部又执行setIncomingCalls更新这个状态。状态更新后依赖项变化会再次触发effect执行,无限循环后导致页面无响应。
另外你维护了4个分类数据状态+1个合并数据状态,属于完全冗余的设计,也额外增加了状态同步的风险。

优化方案

直接移除冗余的5个状态,通过useMemo基于Redux获取的原始数据直接计算合并后的表格数据源即可,优化后代码如下:

import { useMemo } from 'react'

// 仅保留必要的弹窗控制状态
const [showIncoming, setShowIncoming] = useState(false);
const [showId, setShowId] = useState('')

// 从Redux获取四类原始数据
const incomingCallList = useSelector((state) => state.incomingCallList);
const {
    loading: loadingCalls,
    error: errorIncCalls,
    incomingCalls: incCalls,
} = incomingCallList;

const outgoingCallList = useSelector((state) => state.outgoingCallList);
const {
    loading: loadingOutCalls,
    error: errorOutCalls,
    outgoingCalls: outCalls,
} = outgoingCallList;

const meetingList = useSelector((state) => state.meetingList);
const {
    loading: loadingMeetings,
    error: errorMeetings,
    meetings: meetings_list,
} = meetingList;

const emailList = useSelector((state) => state.emailList);
const {
    loading: loadingEmails,
    error: errorEmails,
    emails: email_list,
} = emailList;

// 拉取数据的逻辑保留
useEffect(() => {
    if(props.contractor._id) {
        dispatch(listIncomingCalls())
        dispatch(listOutgoingCalls())
        dispatch(listMeetings())
        dispatch(listEmails())
    }
}, [props.contractor._id, dispatch])

const showIncomingModalHandler = id => {
    console.log(id)
}

// 用useMemo计算合并后的表格数据,仅在依赖变化时重新计算
const data = useMemo(() => {
    const mergedList = []
    const targetContractorId = props.contractor._id

    // 转换并加入来电数据
    if(incCalls) {
        const transformedIncoming = incCalls
            .filter(call => call.contractor._id === targetContractorId)
            .map(c => ({
                type: 'Incoming Call',
                contact_person: c.contact_person,
                logged_by: c.created_by.name,
                date: c.time_created,
                link: <Button onClick={() => showIncomingModalHandler(c._id)}><Eye /></Button>
            }))
        mergedList.push(...transformedIncoming)
    }

    // 转换并加入去电数据
    if(outCalls) {
        const transformedOutgoing = outCalls
            .filter(call => call.contractor._id === targetContractorId)
            .map(c => ({
                type: 'Outgoing Call',
                contact_person: c.contact_person,
                logged_by: c.created_by.name,
                date: c.time_created,
                link: <> <LinkContainer to={`/outgoing-calls/${c._id}`} className='text-success' style={{ cursor: 'pointer'}}><Eye /></LinkContainer> </>
            }))
        mergedList.push(...transformedOutgoing)
    }

    // 转换并加入会议数据
    if(meetings_list) {
        const transformedMeeting = meetings_list
            .filter(meeting => meeting.contractor._id === targetContractorId)
            .map(m => ({
                type: 'Meeting',
                contact_person: m.held_with,
                logged_by: m.logged_by.name,
                date: m.meeting_time,
                link: <> <LinkContainer to={`/meeting/${m._id}`} className='text-success' style={{ cursor: 'pointer'}}><Eye /></LinkContainer> </>
            }))
        mergedList.push(...transformedMeeting)
    }

    // 转换并加入邮件数据
    if(email_list) {
        const transformedEmail = email_list
            .filter(email => email.contractor._id === targetContractorId)
            .map(e => ({
                type: 'Email',
                contact_person: e.contact_person,
                logged_by: e.logged_by.name,
                date: e.date,
                link: <> <LinkContainer to={`/emails/${e.contractor._id}/`} className='text-success' style={{ cursor: 'pointer'}}><Eye /></LinkContainer> </>
            }))
        mergedList.push(...transformedEmail)
    }

    return mergedList
}, [incCalls, outCalls, meetings_list, email_list, props.contractor._id])

// 列配置保留
const columns = [
    { name: 'Action', selector: 'link', sortable: true },
    { name: 'Activity Type', selector: 'type', sortable: true },
    { name: 'Contact Person', selector: 'contact_person', sortable: true },
    { name: 'Logged By', selector: 'logged_by', sortable: true },
    { name: 'Date', selector: 'date', sortable: true }
]

优化收益

  • 彻底消除了循环依赖导致的无限重渲染问题
  • 移除了冗余的状态维护逻辑,代码更简洁易读
  • 数据源计算逻辑集中,后续修改转换规则只需修改useMemo内部逻辑即可,维护成本更低

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 14:24:04