最後就來慢慢將兩者結合吧,先來基礎連接
首先當然是建立兩者的環境
npx create-react-app ws-app
cd ws-app
npm install ws
環境建好就可以開始寫了,那我們先把ws-server搭起來
const WebSocket = require("ws");
// 創建 WebSocket 服務器,監聽端口 8080
const wss = new WebSocket.Server({ port: 8080 });
// 每當有新的客戶端連接時觸發
wss.on("connection", function connection(ws) {
console.log("客戶端已連接");
// 當收到客戶端消息時觸發
ws.on("message", function incoming(message) {
ws.send(`ws: ${message}`);
});
// 當客戶端斷開連接時觸發
ws.on("close", function close() {
console.log("客戶端已斷開連接");
});
});
// 定時每 10 秒廣播當前連接的客戶端數量
setInterval(() => {
const numClients = wss.clients.size; // 當前連接的客戶端數量
// 向每個已連接的客戶端發送當前連接數量
console.log("當前連接的客戶端數量:", numClients);
}, 10000);
console.log("WebSocket 服務器運行在 ws://localhost:8080");
註解直接放進去,特別的就是監控Client的連接數量,該怎麼說在用React連接時有很多的意外,就裝了這個好觀察
就直接把原本的App.js替換成以下
import React, { useEffect, useState } from 'react';
function WebSocketComponent() {
const [message, setMessage] = useState('');
const [serverMessage, setServerMessage] = useState('');
const [ws, setWs] = useState(null);
useEffect(() => {
// 建立 WebSocket 連接
const ws = new WebSocket('ws://localhost:8080');
// 當 WebSocket 連接成功時觸發
ws.onopen = () => {
console.log('WebSocket 連接成功');
setWs(ws);
};
// 當從服務器收到消息時觸發
ws.onmessage = (event) => {
console.log('收到服務器消息:', event.data);
setServerMessage(event.data); // 更新收到的消息
};
// 當 WebSocket 連接關閉時觸發
ws.onclose = () => {
console.log('WebSocket 連接關閉');
};
// 當 WebSocket 出現錯誤時觸發
ws.onerror = (error) => {
console.error('WebSocket 錯誤:', error);
};
// 在組件卸載時關閉 WebSocket 連接
return () => {
ws.close();
};
}, []);
// 發送消息到服務器
const sendMessage = () => {
console.log(message);
ws.send(message);
};
return (
<div>
<h1>WebSocket 測試</h1>
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}></input>
<button onClick={sendMessage}>發送消息</button>
<p>伺服器返回的消息:{serverMessage}</p>
</div>
);
}
export default WebSocketComponent;
如果還有印象,可以發現ws的回傳透過React的useState直接渲染到前端頁面,比起用js+html還簡單非常多,且易懂
const ws = new WebSocket('ws://localhost:8080');
必須放在useEffect中,因為組件會不斷渲染且不會被算在卸載,會導致連接數量一直上升,可以試著移到外面觀察。
結論:
更新10/5
這邊更新一下你在這邊用完之後可能會發現console那邊怎麼出現連接錯誤又成功呢?
那是因為 React 的 Strict Mode 導致的雙重渲染行為
,導致useEffect照理來說的只會觸發一次但因為Strict Mode
的關係二次觸發,導致連接兩次WebSocket也因此第一次被第二次打掉,就會報錯,但實質上是不影響的還是可以連接成功
如果把index.js下面改成
root.render(
<App />
);
就能發現錯誤消失,也能透過useRef 來儲存 WebSocket 連接,就是這樣囉