Open jonny-dungeons opened 4 months ago
Anybody using this hook library? If so I'd like to know if there is a way for sender to emit/broadcast to receiver. This would help me build the typing indicator that lets receiver see that user is typing.
You need a server in the middle to relay messages to other Websocket connections. Use webRTC if you want a peer to peer connection.
Here's a barebones example that sends a 'typing' indicator to the server, which then relays that back to other connected clients, which then displays who is typing within the same component (a chat application would need to be more fleshed out in reality). The component only sends when e.target.value.length changes from 0 to 1 or 1 to 0, to stop unnecessary messages:
Component:
import useWebSocket from 'react-use-websocket';
import { useRef } from 'react';
interface ITypingIndication {
action: 'typing';
typing: boolean;
}
interface ITypingMessage {
type: 'typing';
typing: boolean;
user: string;
}
function MessageForm() {
const { sendMessage, readyState, lastMessage } = useWebSocket(`wss://${window.location.host}/chat`);
const typingMessage: ITypingMessage = (() => {
try {
return JSON.parse(lastMessage);
} catch (e) {
return { type: 'typing', typing: false, user: ''}
}
})();
const lastTypingSent = useRef(false);
const handleTyping: React.ChangeEventHandler<HTMLTextAreaElement> = (e) => {
if (readyState !== 1) {
return;
}
const typing = !!e.target.value;
if (lastTypingSent.current === typing) {
return;
}
const data: ITypingIndication = {
action: 'typing',
typing,
};
lastTypingSent.current = typing;
sendMessage(JSON.stringify(data));
};
return (
<>
{lastMessage.type === "typing" && lastMessage.typing && (
<span>{lastMessage.username} is typing...</span>
)}
<textarea onChange={handleTyping} />
</>
)
}
Server (express handler):
import WebSocket from 'ws';
import { INext, IReq, IRes } from '../types/express';
type UserAction = ITypingIndicator // | (other types of user actions messages)
interface ITypingMessage {
type: 'typing';
typing: boolean;
user: string;
}
const sockets = [];
function websocketHandler(ws: WebSocket, req: IReq, next: INext) {
sockets.push(ws);
ws.on('message', (msg: WebSocket.RawData) => {
if (!req.user) {
return;
}
const data: UserActions = JSON.parse(msg.toString());
const { action } = data;
if (action === 'typing') {
try {
const { username } = req.user;
const typingMessage: ITypingMessage = {
type: 'typing',
typing,
username,
};
const jsonString = JSON.stringify(typingMessage);
sockets.forEach((ws) => ws.send(jsonString));
} catch (error) {
console.log(error);
}
}
In a scenario where you have 2 users chatting is there any way for the receiver to know when the sender is typing using your hook?