[英]How to avoid infinite re-rendering with event listener in React Component?
[英]How to prevent infinite re-rendering with useEffect() in React?
我是開發新手。我使用 socket.io 創建了一個聊天應用程序。我只有在套接字更改時才會更改 useEffect,但我在 useEffect() 的主體中有 setMessage 意味着更新消息,我將套接字作為依賴項。但是這個不起作用,它無限地重新運行。
import React from 'react';
import ScrollToBottom from 'react-scroll-to-bottom';
import { useState,useEffect } from 'react';
function Chat({socket,username,room}) {
const [currentMessage, setCurrentMessage] = useState("");
const [messageList, setMessageList] = useState([]);
const sendMessage = async () => {
if (currentMessage !== "") {
const messageData = {
room: room,
author: username,
message: currentMessage,
time: new Date(Date.now()).getHours()
+ ':' +
new Date(Date.now()).getMinutes()
};
await socket.emit("send_message", messageData);
sendMessage((list)=>[...list,messageData]);
}
};
useEffect(() => {
socket.on("receive_message", (data) => {
setMessageList((list) => [...list, data]);
setCurrentMessage("");
});
}, [socket]);
return (
<div className='chat-window'>
<div className='chat-header'>
<p>Live Chat</p>
</div>
<div className='chat-body'>
<ScrollToBottom className='message-container'>
{messageList.map((messageContent)=>{
return (
<div className='message' id={username===messageContent.author?"you":"other"}>
<h1>{messageContent.message}</h1>
</div>
);
})}
</ScrollToBottom>
</div>
<div className='chat-footer'>
<input type="text" value={currentMessage}placeholder='Hey..' onChange={(event) => {
setCurrentMessage(event.target.value);
}}
onKeyPress={(event)=>{
event.key==='Enter'&&sendMessage();
}}/>
<button onClick={sendMessage}>►</button>
</div>
</div>
);
}
export default Chat;
如何停止渲染 useEffect function?
sendMessage Function 發生遞歸,導致死循環。
刪除以下行可能會解決問題
sendMessage((list)=>[...list,messageData]);
另外,不要忘記從依賴項數組中刪除套接字。
實際上我最近遇到了這個問題,但是您可以嘗試一些選擇:
不要將套接字傳遞給子組件,而應該只將數據傳遞給子組件
示例index.js
:
const [messageList, setMessageList] = useState([]);
// Do not use any deps here
useEffect(() => {
let socket = init() // or something
socket.on("receive_message", (data) => {
setMessageList((list) => [...list, data]);
setCurrentMessage("");
});
}, [])
return (
<ChildComponent messageList={messageList} />
)
使用這個解決方案, useEffect
應該只渲染一次,但是如果你想傳遞套接字,你可以使用useRef
而不是useEffect
,因為它不會重新渲染並且像普通變量一樣工作。
我知道你想在這里擁有干凈的代碼,所以也許替代方案是使用 EventTarget.dispatchEvent() 瀏覽器 API,這種方法是我通常使用的方法。
有了這個,您只需要創建自定義掛鈎來發出/收聽數據,這是我的:
const [data, setData] = useState<T | null>(null);
useEffect(() => {
const handler = ((event: CustomEvent<CustomEventDetail>) => {
if (event.detail.emitId === id) return;
setData(event.detail.data);
}) as EventListener;
window.addEventListener(eventName, handler);
return () => {
window.removeEventListener(eventName, handler);
};
}, [eventName, id]);
const emit = (data: T) => {
const customEvent = new CustomEvent<CustomEventDetail>(eventName, {
detail: {
emitId: id,
data: data,
},
});
setData(data);
window.dispatchEvent(customEvent);
};
useEffect
中創建Validator也許您想嘗試的最后一件事就是使用驗證器
useEffect(() => {
socket.on("receive_message", (data) => {
if (currentMessage !== data.message) {
setMessageList((list) => [...list, data]);
setCurrentMessage("");
}
});
}, [socket]);
但是,我不知道它是否適用於 don`t
另外對於筆記,不要忘記在useEffect
上使用 return ,所以它里面的 function 不會因為組件重新渲染而被多次調用,例如
const handler = () => {}
socket.on("receive_message", handler);
return () => {
socket.off("receive_message", handler);
}
希望我的評論能給你一個解決方案,讓我知道以上是否適合你!
為什么要將 receive_message 套接字偵聽器傳遞給 useEffect? 你試過不使用 useEffect
socket.on("receive_message", (data) => {
setMessageList((list) => [...list, data]);
setCurrentMessage("");
});
我認為您不必將套接字作為依賴項傳遞。
測試這個片段,讓我知道它是否有效。
useEffect(() => {
socket.on("receive_message", (data) => {
setMessageList((list) => [...list, data]);
setCurrentMessage("");
});
return () => {
socket.off('receive_message');
}
}, []);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.