React reducer状态数组追加元素时每次新增元素重复翻倍
问题根因
你的reducer写法本身没有问题,数组重复翻倍的核心原因是socket事件监听器被重复注册,同一条消息触发了多次dispatch,最终表现为列表元素倍增:
- 你写的
socket.on事件绑定放在useEffect里,但没有写清理逻辑移除旧的监听器 - 你把
messages加入了useEffect的依赖数组:每次新消息dispatch后,Redux存储的messagelist更新,组件重渲染,messages引用变化就会触发useEffect重新执行,新增一个socket监听器
实际触发的倍增流程:
- 组件首次挂载,注册1个socket监听器
- 第1条消息到达,1个监听器触发,dispatch1次,列表长度变为1;列表更新触发重渲染,useEffect重跑,再注册1个新监听器,此时总共有2个监听器
- 第2条消息到达,2个监听器同时触发,各dispatch1次,列表一次性加2条,总长度变为3;列表更新再次触发重渲染,useEffect重跑再新增2个监听器,总共有4个监听器
- 后续消息到达时,监听器数量呈指数级上涨,每次dispatch的次数翻倍,最终表现为列表元素每次更新就重复翻倍
修复方案
修改messagelist.js中的useEffect逻辑:
- 移除依赖数组中不必要的
messages依赖,socket事件绑定仅需在组件挂载时执行一次 - 增加useEffect清理函数,每次effect重跑、组件卸载前主动移除已绑定的socket监听器,避免重复绑定
修复后的代码片段:
const messages = useSelector((state) => state.messagelist) const dispatch = useDispatch() useEffect(() => { const handleReceiveMessage = (payload) => { console.log("socket payload", payload); dispatch({type:"newMessage", payload: payload}) } // 绑定事件监听 socket.on("user-to-admin", handleReceiveMessage) // 清理函数:移除旧的监听 return () => { socket.off("user-to-admin", handleReceiveMessage) } }, [dispatch]) // dispatch是引用稳定值,不会触发effect重复执行 let list = () => { return messages.map((e) => <ChatBubble who={e.who} message={e.message} />); }; return <ul>{list()}</ul>
额外可以清理的冗余代码:你定义的const [data, setData] = useState([])全程没有实际使用,对应的data === undefined判断也是无效逻辑,可以直接删除。
内容的提问来源于stack exchange,提问作者Karthik
相关产品推荐
相关产品推荐

