React循环渲染组件出现DOM重叠问题的原因排查及代码示例
问题解决:WebSocket子组件循环渲染时DOM重叠
问题根源
循环渲染子组件时出现DOM内容重叠,核心原因是共享WebSocket实例的消息监听被覆盖:
- 所有子组件共用同一个WebSocket连接,每次直接给
socket.onmessage赋值都会覆盖之前的回调函数,最终只有最后一个子组件的回调生效,导致所有组件显示同一份数据。 - 未在组件卸载时清理监听,旧的回调可能继续触发,引发不必要的状态更新。
- 父组件使用数组索引
idx作为key,数据变动时React可能错误复用组件,加剧渲染异常。
解决方案
1. 用事件监听替代直接赋值onmessage
通过addEventListener添加消息监听,允许多个回调并存;同时在组件卸载时移除监听,避免内存泄漏。
2. 匹配组件专属数据
在消息回调中校验返回数据的number是否与当前组件的num一致,确保只更新当前组件的状态。
3. 优化父组件的key值
用唯一标识(如allot.number)替代数组索引作为key,保证React正确识别组件身份。
修正后的代码
子组件
import { useContext, useEffect, useState } from "react"; import { WebsocketContext } from "./Wsconnection"; import React from "react"; const Allotments = ({ num }) => { const [isReady, socket] = useContext(WebsocketContext); const [allotdata, setAllotdata] = useState({}); useEffect(() => { if (!isReady) return; // 定义专属消息处理函数 const handleMessage = (e) => { const data = JSON.parse(e.data); // 只处理当前组件对应的num的数据 if (data.type === "get_allotment_details" && data.number === num) { const altdata = data.alloted_details[0]; setAllotdata({ customer: altdata.prq__customer__name }); } }; // 发送请求 socket.send(JSON.stringify({ type: "get_allotment_details", number: num })); // 添加事件监听 socket.addEventListener("message", handleMessage); // 清理函数:移除监听,避免内存泄漏 return () => { socket.removeEventListener("message", handleMessage); }; }, [isReady, num, socket]); return ( <div> <h5>{allotdata?.customer}</h5> </div> ); }; export default Allotments;
父组件
import React from "react"; import Allotments from "./Allotments"; const init_alloted = JSON.parse(document.getElementById("reporting").dataset.alloted) || []; export const Alloted = () => { const allots = init_alloted.map((allot) => { // 使用唯一的allot.number作为key,避免组件复用异常 return ( <div key={allot.number}> <Allotments num={allot.number} /> </div> ); }); return <div className="col">{allots}</div>; };
内容的提问来源于stack exchange,提问作者Harish Ahuja
相关产品推荐
相关产品推荐

