1. 引言
WebSocket
是一种在Web
应用中实现双向通信的协议。它允许服务器主动向客户端推送数据,而不需要客户端发起请求。在现代的实时应用中,WebSocket
经常用于实时数据传输、聊天功能、实时通知和多人协作等场景。在本篇博客中,我们将探索如何在React 18
应用中使用WebSocket
来实现实时通信。
2. 准备工作
在开始之前,我们需要安装React 18
,并确定你已经掌握了React Hooks
的基本知识。此外,我们还将使用WebSocket
的npm包来实现WebSocket
连接。你可以通过以下命令使用npm
或yarn
来安装它:
npm install websocket
# 或
yarn add websocket
3. 编写自定义钩子
import { useEffect, useRef, useState } from 'react';
import WebSocketClient from 'websocket';
export function useWebSocket(accessToken: string, requestName: string): SocketType {
const clientRef = useRef<WebSocketClient | null>(null);
const [isActive, setIsActive] = useState<boolean>(false);
const [socketClient, setSockClient] = useState<WebSocketClient | null>(null);
// 获取url
let port = window.location.port;
let wsUrl = '';
if (window.location.protocol === 'https:') {
//如果当前是HTTPS加密的,那么使用wss
if (!port) {
port = '4174';
}
wsUrl = 'wss:';
} else {
if (!port) {
port = '8080';
}
wsUrl = 'ws:';
}
wsUrl +=
`//${window.location.hostname}:${port}/api/ws/plugins/${requestName}?token=` +
accessToken;
if (!socketClient) {
setSockClient(new WebSocketClient(wsUrl, isActive)); // 创建 WebSocketClient 实例并传入 URL 和活动状态 isActive
}
useEffect(() => {
clientRef.current = socketClient;
if (!socketClient?.socket) {
socketClient?.start(); // 启动WebSocket连接
}
return () => {
socketClient?.close(); // 组件卸载时关闭WebSocket连接
};
}, []);
// 建立 WebSocket 连接
const connect = () => {
const client = clientRef.current;
if (client) {
client.connect(); // 建立WebSocket连接
}
};
// 关闭 WebSocket 连接
const close = () => {
const client = clientRef.current;
if (client) {
client.close(); // 关闭WebSocket连接
}
};
// 订阅消息处理程序
const subscribe = (handler: MessageHandler) => {
const client = clientRef.current;
setIsActive(true);
if (client) {
client.subscribe(handler);
}
};
// 取消订阅消息
const unsubscribe = () => {
const client = clientRef.current;
if (client && isActive) {
setIsActive(false);
client.unsubscribe();
}
};
// 发送消息
const send = (message: string) => {
const client = clientRef.current;
if (client && client.socket?.readyState === WebSocket.OPEN) {
client.send(message); // 发送消息
} else if (client && client.socket?.readyState === WebSocket.CLOSED) {
// WebSocket连接未建立或已关闭,需要重新建立连接
client.connect(); // 建立WebSocket连接
}
};
return { connect, close, subscribe, unsubscribe, send };
}
在上述代码中,我们使用useRef
来保存WebSocketClient
实例,使用useState来管理isActive
和socketClient
状态。通过创建WebSocket
连接的URL和accessToken
,我们可以在useEffect钩子中实例化WebSocketClient
。然后使用useEffect
钩子来启动和关闭WebSocket连接,并在组件卸载时关闭连接。
4. 创建WebSocketProvider
为了在整个应用中共享WebSocket
连接对象,我们需要创建一个WebSocketProvider
组件。这个组件将使用提供者模式将连接对象提供给子组件。
在你的项目中创建一个名为WebSocketProvider
.js的文件,并添加以下代码:
import React, { useContext, useEffect } from 'react';
import { useWebSocket } from './useWebSocket';
const WebSocketContext = React.createContext();
export const useWebSocketContext = () => {
return useContext(WebSocketContext);
};
export const WebSocketProvider = ({ children, accessToken }) => {
const webSocket = useWebSocket(accessToken);
useEffect(() => {
webSocket.connect();
return () => {
webSocket.close();
};
}, [webSocket]);
return (
<WebSocketContext.Provider value={webSocket}>
{children}
</WebSocketContext.Provider>
);
};
在上述代码中,我们使用useWebSocket
钩子来获取WebSocket
连接对象,并在useEffect
钩子中连接WebSocket
,并在组件卸载时关闭连接。然后,我们将连接对象提供给子组件,通过创建一个WebSocketContext.Provider
。
5. 在组件中使用共享连接
现在,我们可以在应用的任何组件中使用共享的WebSocket
连接了。
假设我们有一个名为ChatComponent
的组件,它需要使用WebSocket
连接来实现实时聊天功能。在ChatComponent.js
文件中,添加以下代码:
import React from 'react';
import { useWebSocketContext } from './WebSocketProvider';
function ChatComponent() {
const webSocket = useWebSocketContext();
const sendMessage = () => {
if (webSocket) {
webSocket.send('Hello, WebSocket!');
}
};
return (
<div>
<button onClick={sendMessage}>Send Message</button>
</div>
);
}
export default ChatComponent;
在上述代码中,我们使用useWebSocketContext
来获取WebSocket
连接对象。然后,我们可以在组件中调用send
方法来发送消息。
6. 示例应用:实时聊天
让我们使用上述代码,创建一个实时聊天应用作为示例。在你的项目中,创建一个名为RealTimeChatApp
的文件夹,然后在文件夹中创建以下文件:
`RealTimeChatApp.js:` 主应用组件
`ChatComponent.js:` 实时聊天组件
`WebSocketProvider.js`: `WebSocket`连接提供者
在RealTimeChatApp.js
中,添加以下代码:
import React from 'react';
import ChatComponent from './ChatComponent';
import { WebSocketProvider } from './WebSocketProvider';
function RealTimeChatApp() {
const accessToken = 'your_access_token'; // 替换为你的访问令牌
return (
<WebSocketProvider accessToken={accessToken}>
<div>
<h1>Real Time Chat App</h1>
<ChatComponent />
</div>
</WebSocketProvider>
);
}
export default RealTimeChatApp;
然后,在ChatComponent.js
中,添加以下代码:
import React from 'react';
import { useWebSocketContext } from './WebSocketProvider';
function ChatComponent() {
const webSocket = useWebSocketContext();
const [messages, setMessages] = React.useState([]);
const [newMessage, setNewMessage] = React.useState('');
React.useEffect(() => {
const messageHandler = (message) => {
setMessages((prevMessages) => [...prevMessages, message]);
};
webSocket.subscribe(messageHandler);
return () => {
webSocket.unsubscribe();
};
}, [webSocket]);
const sendMessage = () => {
if (webSocket) {
webSocket.send(newMessage);
setNewMessage('');
}
};
return (
<div>
<div>
{messages.map((message, index) => (
<div key={index}>{message}</div>
))}
</div>
<div>
<input
type="text"
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
/>
<button onClick={sendMessage}>Send</button>
</div>
</div>
);
}
export default ChatComponent;
最后,启动你的应用,访问RealTimeChatApp
组件,即可在浏览器中查看实时聊天功能。
7. 总结
本文介绍了如何在React 18
应用中使用WebSocket
来实现实时通信,并展示了如何通过自定义钩子和提供者模式来共享WebSocket
连接对象。通过这种方式,我们可以在多个组件中使用同一个连接对象,从而避免了不必要的连接重复实例化和性能开销。WebSocket
在现代实时应用中发挥着重要作用,帮助我们实现更高效的通信和用户体验。
希望本文能够帮助你理解如何在React 18
中使用WebSocket
,并在应用中实现共享连接的目标。如果你想进一步探索WebSocket
的高级用法,可以深入了解WebSocket
的各种选项和特性,以满足你的实际需求。
致谢
感谢您阅读本文,希望本文对你有所帮助。特别感谢React 18
和WebSocket
社区的开发者们,为我们提供了强大的工具和技术,让实时通信变得更加简单和高效。