Use Node and Socket to implement online chat rooms
Introduction to the
In H5 end through socket to achieve the function of online chat room, server based on Node.
This tutorial is intended to simplify the implementation process of socket and Node. So the H5 static page development step is skipped.
Static pages
Here as far as possible with the simplest code to achieve the development of a static page, the whole page is divided into two parts:
1. Chat window. Focus on the data structure of the objects in the chat object list
parameter | instructions | type |
---|---|---|
id | – | string | number |
name | The user name | string |
type | The message type can be text, picture, or expression | text | img 等 |
message | The message content | – |
2, the bottom input box.
Branch: feat- h5-static-Page Branch of the static page
Second, establish a connection
node
In this demo, the function of the server is to transfer messages. Send the message sent by Xiaoming to everyone through the Node socket. The message structure and content can remain unchanged.
At present, there are two libraries used by developers: socket. IO and WS.
socket.io
The domain name ishttp://
ws
The domain name isws://
So socket. IO meets the needs of actual projects. Here’s the socket. IO to implement the demo.
Project initialization
mkdir nodePkg
cd nodePkg
yarn init
yarn add express
yarn add node
yarn add socket.io
Copy the code
Create a new folder to hold our Node project, and after the project is initialized, add a few libraries to use.
Create a new server.js file to implement the functionality.
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const app = express();
const server = http.Server(app);
const io = socketIo(server);
io.on('connection'.function (socket) {
console.log(socket);
});
server.listen(3000);
app.listen(8080.'localhost'._= > {
console.log('Demo server started, access address http://localhost:8080')})Copy the code
connection
When a client initiates a connection, the server can passconnection
Establish a connection.server.listen
Socket connection port: 3000app.listen(8080, '', () => {})
The node service
Start the service
node server.js
Copy the code
After writing the server, we now develop the Web side to test whether the connection can be successfully established.
web
Pull the code from the H5 branch above and install the required libraries.
yarn add socket.io-client
Copy the code
Write the SRC/pages/index/index. The benchmark, the following code as the thumbnail content
import React, { FC, useEffect, useState } from 'react';
import io from 'socket.io-client';
const HomePage: FC<HomePageProps> = ({ location }) = > {
const [socket] = useState<any>(
io('http://localhost:3000', { transports: ['websocket']}));console.log(socket);
}
Copy the code
We may find a connection failure when we start the project Web project. Don’t worry. It takes time for the Node socket to start for the first time.
When we see the Console on the Web side printing connected: true, and the Node server on(‘connection’) has a printed message on the terminal. The connection has been successfully established.
Branch: feat-connect Establish a connection branch
Send and receive messages
node
There are omitted parts of repeated code
. io.on('connection'.function (socket) {
socket.on('message'.function (data) {
console.log('Server receives:', data);
socket.send(data);
});
socket.on('error'.function (err) {
console.log(err); }); }); .Copy the code
socket.on('message'
Here,message
The value must be consistent with that on the Web server so that the two ends can communicate with each other.socket.send(data);
The received message is forwarded again.
web
. useEffect(() = > {
socket.on('message'.(msg: any) = > {
console.log(msg);
setChatList([...chatList, msg]);
});
}, [socket]);
const sendMessage = () = > {
socket.emit('message', {
id: random(),
name,
type: 'text'.message: inputValue, }); }; .Copy the code
socket.on
The Web end receives socket messages. Proceduresocket.emit
Send a socket message.'message'
Be consistent so that both ends can communicate with each other.
Restart the node service to check the effect.
Ok, so now we have successfully established the connection. But a careful observer will notice:
- in
socket.on('message'
There’s no way to get it in real timechatList
The list cannot be appended. - At this time, if the Web side opens another page to send messages, the two pages do not communicate with each other.
Multiplayer chat rooms
node
The last legacy problem exists two pages connected to the same socket does not communicate with the problem, together to solve the ~
If you look at the current node code, you will find that each socket only receives and sends data to the current socket after establishing a connection. Therefore, different sockets cannot communicate with each other.
The solution is: we store all socket connections, and each time a socket receives a message, we iterate over each socket and send the message.
let socketSet = new Set(a);/ / store the socket
io.on('connection'.function (socket) {
socketSet.add(socket);
socket.on('message'.function (data) {
socketSet.forEach(ws= > {
if (ws.connected) { // Check whether the current socket is connected
ws.send(data);
} else{ socketSet.delete(ws); }})}); socket.on('error'.function (err) {
console.log(err);
});
});
Copy the code
Let’s verify the effect. As you can see from the following figure, the message is sent in the right chat box and the message is received in the left chat box.
web
Web side let’s optimize a few small problems:
- The chat input box is empty after the message is sent
- Use useRef to keep chat logs up to date
Feat – Multi-chat branch (feat-multi-chat branch
import React, { FC, useEffect, useState, useRef } from 'react';
const chatListRef = useRef<any[]>([]);
useEffect(() = > {
chatListRef.current = chatList;
setChatList(chatList);
}, [chatList]);
useEffect(() = > {
socket.on('message'.(msg: any) = > {
setChatList([...chatListRef.current, msg]);
chatListRef.current = [...chatListRef.current, msg];
});
}, [socket]);
const sendMessage = () = >{... setInputValue(' ');
};
Copy the code
Five, external functions
Mention a few small function points and optimization points, through the text description to achieve.
1. Loading state
Added a loading flag to the chatList object array.
Set sending to false, or set data loading to true if socket. On (‘message’,{}) listens for messages sent by the current ID.
And that’s going to simulate sending a message and whether it’s successful or not.
2, increaseenter
Listen for an event
// Keyboard binding events
const handleEnterKey = (e: any) = > {
if (e.keyCode === 13) {
// Call the method that sends the message}}; useEffect(() = > {
document.addEventListener('keypress'.(e) = > handleEnterKey(e));
return () = > document.removeEventListener('keypress'.(e) = >handleEnterKey(e)); } []);Copy the code