[英]Why is my react element rendering many times?
问题:我有以下反应组件。 基本上,我正在构建一个与 socket.io 反应的聊天应用程序
import { io } from 'socket.io-client';
const socket = io(ServerEndURL);
export default function Chat (props) {
const uuid = props.uuid;
const classes = useStyles();
const [open, setOpen] = useState(false);
const [btnColor, setBtnColor] = useState('white');
const [activeStatus, setActiveStatus] = useState('Offline');
const [unreadMsgs, setUnreadMsgs] = useState(0);
const [msgArr, setMsgArr] = useState([]);
const chatBtnRef = useRef();
const chatBoxRef = useRef();
const msgInputRef = useRef();
useEffect(() => {
socket.emit('join', uuid);
socket.emit('isActive', uuid);
return () => {
console.log('removed');
socket.off('newMsg');
}
}, []);
socket.on('newMsg', msg => {
console.log('debug');
let msgs = msgArr.map(msg => msg);
msgs.push({
type : 'received',
msg,
});
setMsgArr(msgs);
if(!open) setUnreadMsgs(unreadMsgs + 1);
chatBoxRef.current.scrollTop = chatBoxRef.current.scrollHeight;
});
当服务器在套接字上触发newMsg事件时,我希望它用新的 msg 更新msgArr state,但我看到console.log('debug')语句运行的次数比预期的要多,而且事情不起作用正如我所期望的那样。 我的意思是,它应该只对一次。 但它没有,它运行多次,在某些时候,“次”甚至达到 40。作为新的反应,我不明白为什么会发生这种情况。 因此,如果有人能对这个问题有所了解,我将不胜感激,这让我好几天都保持清醒。 我需要帮助。 任何人?
看起来您正在尝试直接突变 state ,这是您永远不应该做的。 试试这个:
import { io } from 'socket.io-client';
const socket = io(ServerEndURL);
export default function Chat (props) {
const uuid = props.uuid;
const classes = useStyles();
const [open, setOpen] = useState(false);
const [btnColor, setBtnColor] = useState('white');
const [activeStatus, setActiveStatus] = useState('Offline');
const [unreadMsgs, setUnreadMsgs] = useState(0);
const [msgArr, setMsgArr] = useState([]);
const chatBtnRef = useRef();
const chatBoxRef = useRef();
const msgInputRef = useRef();
useEffect(() => {
socket.emit('join', uuid);
socket.emit('isActive', uuid);
return () => {
console.log('removed');
socket.off('newMsg');
}
}, []);
socket.on('newMsg', msg => {
console.log('debug');
// Note: This is a no-op if you don't need to extract info from `msg`
let msgs = msgArr.map(msg => msg);
// Update state directly with the new message
setMsgArr([ ...msgs, { type: 'received', msg }]);
if(!open) setUnreadMsgs(unreadMsgs + 1);
chatBoxRef.current.scrollTop = chatBoxRef.current.scrollHeight;
});
对于问题的第二部分,您告诉 React 您希望将什么呈现到 DOM 中,然后它负责代表您实际更新 DOM。 因此,如果需要,它可能会多次重新渲染您的组件(通常是在 state 已更新时)。 在您的情况下,您为更新 state 的newMsg
事件定义事件处理程序,因此当触发此事件处理程序时,React 会重新呈现您的组件(执行console.log('debug')
语句)。
我的假设是,每次 react 渲染组件时,您都会继续订阅 newMsg 事件。 如果您的组件重新渲染 40 次,您将有 40 次订阅您的“newMsg”事件,并且它将运行您的事件回调 40 次。 那说:
改为在 'useEffect' 挂钩中定义您的 'newMsg' 事件侦听器。
只要您仅证明一个空数组([])作为您的第二个参数,就可以在您现有的“useEffect”中:
useEffect(() => {
socket.on('newMsg', ...)
socket.emit('join', uuid);
socket.emit('isActive', uuid);
return () => {
console.log('removed');
socket.off('newMsg');
}
}, []);
或者,如果您的逻辑发生变化并且您“监控”原始“useEffect”中的变化,您可以简单地将其放在自己的位置。 (示例包括消息数组)
const [msgArr, setMsgArr] = useState([]);
useEffect(() => {
socket.on('newMsg', msg => {
setMsgArr([ ...msgArr, { type: 'received', msg }]);
//Alternative:
//setMsgArr(msgArr.concat({ type: 'received', msg }));
})
}, []);
'useEffect' 中的第二个参数只是告诉 react 如果您的第二个参数中的某些内容发生更改,则重新运行效果。 但是,您只想订阅一次,因此提供了一个空数组,因此它永远不会看到更改并重新运行效果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.