Learning Something New ๐#
Recently, I have been learning React, so the main purpose of this project is to familiarize myself with React. I personally like to learn new things while getting hands-on experience. Only by outputting can I have a deeper memory. In addition, I may encounter some pitfalls that I wouldn't encounter just by reading. Since I didn't do much with node.js before, I thought of combining it with a chat room. โ
Since this is my first time using React, if you feel that there is anything that needs to be modified, please feel free to raise an Issue, and I also welcome your starโญ
Project link: ChatRoom
Project screenshots:
Backend#
Backend is based on Node.js + Express + Socket.io + MongoDB
I have roughly summarized the operations of Node.js with MongoDB and writing interfaces using Express in my blog before:
Node.js+express
Node.Js ๆไฝ MongoDB
The new thing used this time is Socket.io.
Previous Work ๐#
Socket.IO is a library that enables real-time, bidirectional and event-based communication between the browser and the server.
In other words, Socket.io can achieve real-time bidirectional communication between the server and the client. Before connecting with Socket.io, you need to know about WebSocket. Before WebSocket was introduced, when creating web applications with bidirectional communication mechanisms, only HTTP polling could be used, resulting in "short polling" and "long polling".
Short polling involves the client regularly polling the server to ask if there is any new information. The disadvantage is obvious. If the polling interval is too long, the information is not real-time enough, and if the interval is too short, it will consume too much traffic and increase the server's burden.
Long polling is an optimization of short polling and requires corresponding modifications on the server side to support it. However, each request still needs to carry the HTTP request header, and after the long polling connection ends, the new messages accumulated on the server side can only be delivered when the client connects next time.
The WebSocket protocol was born to solve the pain points of long polling. It is based on the TCP protocol and is a full-duplex communication technology that reuses the HTTP handshake channel. The only relationship with HTTP is that its handshake request can be parsed by an HTTP server as an Upgrade request, and it uses the same port as HTTP.
Next is Socket.io. Socket.io is based on engine.io and encapsulates WebSocket. It shields the underlying details and makes the top-level calls very simple. At the same time, it supports many polling mechanisms and other communication methods. When the environment does not support WebSocket, it can automatically choose the best way to achieve real-time communication over the network.
Usage#
Import io and set the port, then listen for the connect event:
const server = require('http').Server(app);
const io = require('socket.io')(server);
server.listen(3001); // Set the port to 3001
io.on(('connection', socket=>{
โฆโฆโฆโฆโฆโฆ
})
Then use the two most important APIs, emit and on, to send and listen for events:
- socket.emit(eventName, [...args]): Emit (trigger) an event.
- socket.on(eventName, callback): Listen for an event emitted by emit.
// Listen for the xxx event and output the data object passed in
socket.on('xxx',data=>{
console.log(data);
})
// Send the xxx event and pass an object with a name property
socket.emit('xxx',{name:'magren'})
Other methods used:
- socket.join(id): Join a room with the id.
- socket.broadcast.to(id).emit(): Broadcast to all people in the room with the id except for 'me'.
- io.sockets.in(id).emit(): Broadcast to all people in the room with the id.
Frontend#
Frontend is based on React + Redux + Typescript + Antd
Sending messages to and listening from the backend is simple, just import socket.io-client and use emit to send and on to listen for events.
const socket = require('socket.io-client')('ws://localhost:3001',{transports: ['websocket']})
// Listen for chat_message event and update the state with the received data
socket.on('chat_message',(data: mesItem)=>{
this.setState({
message:[data,...this.state.message]
});
})
// Send join event to join a group
socket.emit('join', {
roomId:this.props.match.params.roomId,
userName:this.props.state.name,
userId:this.props.state.id
})
// Send mes event to send a message
socket.emit('mes',{
roomId:this.props.match.params.roomId,
userName:this.props.state.name,
userId:this.props.state.id,
mes:this.state.msg
})
About Redux#
The concept of redux is similar to vuex. Both are state management libraries, and the state is stored in memory (reset when refreshed). They define global state and trigger state changes. However, there are also differences. Vuex data is mutable and can be directly modified, while Redux is immutable and replaces the old state with a new state.
This project uses two libraries: react-redux and redux-thunk.
After using react-redux, the process is greatly shortened. The three main functions of the store: dispatch, subscribe, and getState are implemented by it. It also provides Provider and Connect, the former being a component and the latter being a function.
The general process is that the Provider component accepts the redux store as props and passes it down through context. The connect function receives the store passed out by Provider and passes the state and actionCreator as props to the component. The component can trigger the reducer function by calling the action in props to return a new state. Connect listens for changes and calls setState to update the component and pass in the new state.
The purpose of redux-thunk is to make store.dispatch able to accept a function/object as middleware.
It allows store.dispatch, which originally only accepts objects, to accept objects/functions, and if it receives a function, it automatically executes the function without triggering a store update in Redux.
Finally ๐ป#
Thanks to search engines like Google and Baidu, and Google Translate ๐ต
And thanks to bailicangdu's react-pxq project for reference and summary ๐