[英]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.