簡體   English   中英

Socket.io 和 React:從服務器接收數據並在組件中設置 state 的正確方法?

[英]Socket.io and React: Proper way too receive data from server and set state in a component?

嘗試運行一個基本的聊天應用程序,但在發送消息時遇到過度重新呈現的問題。 這是客戶端的適用代碼:

const [chatMessages, setChatMessages] = useState([]);
const sendChat = (e) => {
    socket.emit("sendMessage", e.target.elements.message.value);
}

useEffect(() => {
  socket.on("receiveMessage", (chatMessage) => {
    setChatMessages([...chatMessages, chatMessage]);
      console.log(chatMessages);
  });
}, [chatMessages]);
return (
    {chatMessages.map((message) => <p>{message}</p>)}
)

然后,在服務器上:

io.on("connection", (socket) => {
    socket.on("sendMessage", (chatMessage) => {
        console.log("message sent");
        io.to(roomId).emit("receiveMessage", chatMessage);
    });
}

當我這樣做時,消息已成功發送和接收,但會導致它發生很多次(控制台):

[]
[]
[{...}]
[{...}]
(2) [{...}, {...}]

在第三條消息中,這是記錄的內容。 到第六條或第七條消息時,整個頁面都停止了,因為它記錄了大約 100 次。

我嘗試了以下方法:

  1. useEffect()中有一個空的依賴數組。 這確實修復了重新渲染,但引入了一個新問題。 最新消息是唯一保存並替換最后一條消息的消息,因此您一次只能看到一條消息。

  2. 將其全部從useEffect()中取出。 這只會使問題惡化,並導致每條消息的重新呈現次數更多。

任何幫助,將不勝感激。 謝謝!

問題

chatMessages state 更新但不清除它們時,您正在創建套接字事件處理程序。 如果您編輯您的代碼或組件重新呈現等......然后添加另一個套接字事件處理程序。 多個處理程序將開始堆疊並排隊多個意外的 state 更新。

此外,由於 React state 更新是異步處理的,您無法在更新排隊后立即記錄 state 並期望看到更新后的 state。為此使用單獨的useEffect掛鈎。

解決方案

  1. 添加useEffect清理 function 以刪除事件處理程序,並在處理程序回調中重新包含更新的chatMessages state 數組。

     useEffect(() => { const handler = (chatMessage) => { setChatMessages([...chatMessages, chatMessage]); } socket.on("receiveMessage", handler); return () => socket.off("receiveMessage", handler); }, [chatMessages]);
  2. 添加一個useEffect清理 function,刪除依賴項以便效果在組件安裝時運行一次,並使用功能性 state 更新從回調附件中的先前 state 而不是初始 state 正確更新。

     useEffect(() => { const handler = (chatMessage) => { setChatMessages(chatMessages => [...chatMessages, chatMessage]); } socket.on("receiveMessage", handler); return () => socket.off("receiveMessage", handler); }, []);

在這兩者之間,第二個選項是更優的解決方案,但你選擇哪個是你的決定。

要記錄聊天消息chatMessages更新:

useEffect(() => {
  console.log(chatMessages);
}, [chatMessages]);

由於您依賴於chatMessages ,每次chatMessages更改時,它都會創建一個新的偵聽器。 這就是為什么當收到更多消息時它變得越來越慢。

你可以做兩件事:

  1. 您在useEffect方法中本地維護chatMessages 您可以展開該數組,然后使用展開的數組調用setChatMessages 執行此操作時,您可以刪除chatMessagesuseEffect的依賴性,並且仍然擁有所有消息。 作為一種好的做法,您應該返回一個 function,它將在組件卸載時刪除事件偵聽器。

 const [chatMessages, setChatMessages] = useState([]); const sendChat = (e) => { socket.emit("sendMessage", e.target.elements.message.value); } useEffect(() => { let localMessages = []; const callback = (chatMessage) => { localMessages = [...localMessages, chatMessage]; setChatMessages(localMessages); console.log(localMessages); }; socket.on("receiveMessage", callback); return () => { socket.off("receiveMessage", callback); } }, []); return ( {chatMessages.map((message) => <p>{message}</p>)} )

  1. 您可能可以使用useRef來存儲值。 但是,當值更改時,這不會觸發 UI 的重新呈現,這可能不是您想要的。 所以這可能不是一個好的選擇。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM