React中useEffect设空依赖数组调用setState仍触发无限循环如何解决?
问题根因
你的无限循环问题和useEffect无关,是button的事件绑定写法错误导致的:
- 你给
onClick直接赋值了onToggleArchived(callInfo.id),这会在组件每次渲染时立即执行这个函数,而不是等到用户点击按钮时才触发。如果onToggleArchived内部会修改父组件的状态,就会触发父组件重渲染,进而让当前的ActivityDetail组件跟着重渲染,重渲染时又会再次执行onToggleArchived,形成死循环。 - 另外你的
useEffect写法存在不规范问题:依赖数组为空但用到了外部的call变量,后续如果call的值更新,callInfo不会同步更新,也会触发Hook依赖检查警告。实际上你完全不需要单独维护callInfo这个冗余状态,直接使用路由拿到的call即可。
修复后代码
import { useLocation } from "react-router-dom"; const ActivityDetail = ({ onToggleArchived }) => { const { call } = useLocation().state; return ( <div> <h3 className="title">通话详情</h3> <hr /> {call && <div> <p>来电方: {call.from}</p> <p>接听方: {call.to}</p> <p>通话时间: {call.created_at}</p> {/* 用箭头函数包裹,点击时才执行逻辑 */} <button onClick={() => onToggleArchived(call.id)}> {call.is_archived ? "取消归档" : "归档"} </button> </div> } </div> ) } export default ActivityDetail
改动说明
- 删除了冗余的
callInfo状态和对应的useEffect,直接使用路由拿到的call数据,减少不必要的状态更新。 - 把
onClick的绑定改为箭头函数包裹onToggleArchived调用,确保只有用户点击按钮时才会执行该函数,避免渲染时自动触发。
如果你确实需要单独维护callInfo状态,只需要做两处修改即可:
- 把
call加入useEffect的依赖数组:useEffect(() => { setCallInfo({ ...call }); }, [call]) - 修正
onClick的绑定写法为箭头函数包裹。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

