Command line to create the React project
npx create-react-app socketio-demo
Copy the code
Go to socketio-demo and run eject to unpack. This project may not be unpacked. It’s a personal habit. Note If you run the eject command, it is best to run it at the initial stage of the project. Do not use the eject command after you have written the project, which may cause bugs
yarn eject
Copy the code
Create server folders and files after the project is unpacked
mkdir server
type null>index.js
Copy the code
The following directories are created
Write instant messaging (chat room) background
Install the NodeJS plug-in
npm i express http socket.io nodemon
Copy the code
Enter the index.js page under the server folder and start writing background programs
const app = require('express') (); const server = require('http').Server(app);
const io = require('socket.io')(server); // Set port 9093 server.listen(9093); // create socket. IO connection IO. On ('connection'.function(socket) {// Get messages event socket.on('messages'.function (data) {
//向所有连接进行广播
socket.broadcast.emit('messages', data) // To broadcast the sender, add me data.user=data.user+'[我]'
socket.emit('messages', data)
});
});
Copy the code
Write im (chat room) receptionist
React-router and Redux dependencies can be written in the SRC directory to install the react-Router and Redux dependencies
npm i redux react-redux react-router react-router-dom
Copy the code
Create the IO folder in SRC. Create the required files in the IO folder
cd src
mkdir io
cd io
type null>login.js
type null>socket-demo.js
type null>socket-demo.css
mkdir auth
cd auth
type null>auth.js
Copy the code
The following directories are created
Here auth.js file is used to judge whether the user enters a nickname. If the user has entered a nickname, he can enter the chat room. If he has not entered a nickname, he will jump back to the login interface and ask for a nickname
In this project, we saved the nickname in redux to realize the common login interface and chat room interface. Of course, this project is relatively small, if you want to use localStorage for localStorage, but considering the later expansibility and deepen the understanding of redux, I still choose to save it in redux
- Create the redux.js file in the SRC folder
- SRC folder to create the redux folder, in the redux folder to create user.redux.js file
cd src
type null>redux.js
mkdir redux
cd redux
type null>user.redux.js
Copy the code
Create a new directory as follows
const SET_USERNAME='SET_USERNAME'// Initialize the repository const initState={user:' '} // Change the warehouse according to the actionexport function User(state = initState, action) {
switch (action.type) {
case SET_USERNAME:
return{... state,user:action.payload} default:returnState}} // Write the nickname actionexport function setUserName(user) {
return {
type:SET_USERNAME,
payload:user
}
}
Copy the code
Create a repository combineReducers in SRC /redux.js for the merge of multiple reducer. It can also be added in this project for later expansion
import { combineReducers, createStore } from 'redux'
import {User} from './redux/user.redux'__REDUX_DEVTOOLS_EXTENSION__ &&window.__redux_devtools_extension__ () is an extension for Chrome Reduxlet reducer = combineReducers({ User })
let store = createStore(
reducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
export default store
Copy the code
This allows you to use Redux in your pages
Next, import redux in app.js and set up the route to write in SRC /app.js
import React from 'react';
import {HashRouter as Router,Route,Switch} from 'react-router-dom'
import Login from "./io/login";
import SocketDemo from "./io/socket-demo";
import {Provider} from 'react-redux'
import store from './redux'
import Auth from "./io/auth/auth";
function App() {
return (
<Provider store={store}>
<Router>
<Auth></Auth>
<Switch>
<Route exact path='/' component={Login}/>
<Route exact path='/talk' component={SocketDemo}/>
</Switch>
</Router>
</Provider>
);
}
export default App;
Copy the code
We install the modifier plug-in before writing the page
npm i babel-plugin-transform-decorators-legacy
Copy the code
Install @babel/plugin-proposal-decorators when Babel >= 7.x
npm i @babel/plugin-proposal-decorators
Copy the code
Json in the Babel item. Note that plugins are placed before presets or errors may occur
"babel": {
"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true}]],"presets": [
"react-app"]}Copy the code
Okay so we can use the decorations
SRC/IO /auth/auth.js
import React from 'react';
import {connect} from 'react-redux'
import {withRouter} from 'react-router-dom'Router@withrouter class Auth extends React.Component{componentDidMount() {// If the user name is available, jump to the chat page, if not, jump to the login page.if(this.props.User.user){
this.props.history.push('/talk')}else {
this.props.history.push('/')}}render() {
return null
}
}
export default Auth
Copy the code
Write the input nickname and skip steps to open the SRC/IO /login.js file
import React from 'react';
import './socket-demo.css';
import {connect} from 'react-redux'
import {setUserName} from '.. /redux/user.redux'
@connect(
null,
{setUserName}
)
class Login extends React.Component{
constructor(props) {
super(props);
this.state={
user:' '} this.login=this.login.bind(this) this.onkeyDown = this.onkeydown.bind (this)} {case 13:
this.login();
return;
default:
return; }} // Add keyboard eventscomponentDidMount() {
document.addEventListener("keydown", this.onKeyDown)} // Assign state handleChange(title,target){this.setState({[title]:target.target.value})} // assign and jump to the chatroom pagelogin() {let {user}=this.state;
if(user! ==null && user.trim()! = =' '){
this.props.setUserName(user);
this.props.history.push('/talk')}}render() {
return (
<div className='loginDiv'>
<input type='text' placeholder='Enter a nickname' onChange={v=>this.handleChange('user', v)} / > < button onClick = {this. Login} > enter the chat room < / button > < / div >). }}export default Login
Copy the code
Here is the highlight. The front end of the chat room shows the core code to open the SRC /iosocket-demo.js file
import React from 'react'
import io from 'socket.io-client'
import {connect} from 'react-redux'
import './socket-demo.css'
const url='ws://localhost:9093'
const socket = io(url);
@connect(
state=>state,
{}
)
class SocketDemo extends React.Component{
constructor(props) {
super(props);
this.state={
message:' ',
user:this.props.User.user,
messages:[]
}
this.send=this.send.bind(this)
this.login=this.login.bind(this)
this.onKeyDown=this.onKeyDown.bind(this)
}
componentDidMount() {/ / input welcome message this. The login () / / increase the enter event document. The addEventListener ("keydown", this.onKeyDown) //socket. IO Connection background IO (url).on('connect', ()=>{
console.log('connect');
socket.on('messages', data = > {/ / return the user list enclosing setState ({messages: [..... This state messages, data]})if(this.refs.showDiv){
this.refs.showDiv.scrollTop=2000
}
});
});
}
componentWillUnmount() {// Disconnect socket IO'ws://localhost:9093').on('disconnect'.function(){
console.log('disconntect');
});
document.removeEventListener("keydown"OnKeyDown (e){switch (e.keycode){this.onkeyDown)}case 13:
this.send();
return; default:
return; }} // Send information to the backgroundsend() {let {user,message}=this.state;
console.log(this.refs.showDiv);
socket.emit('messages', {user,message});
this.setState({
message:' '})}login() {let user=this.props.User.user;
const obj={user:'the writer'Message: ` welcome${user}Go to chat room '}if(user.trim()! = =' '){ this.setState({ user:user, Messages :[obj]})} // Assign state handleChange(title,target){this.setState({[title]:target.target.value})}render() {
let cn='showInfo'
return (
<div>
<div className='talkDiv'>
<div className='operatingDiv'>
<input type='text'
placeholder='Please enter your chat information here'
onChange={v=>this.handleChange('message',v)} value={this.state.message} /> <button onClick={this.send}> </button> </div> <div ref='showDiv' className='showDiv'>
{
this.state.messages.map((v,index)=>{
if(index===0){
cn='titleInfo'
}else{
cn='showInfo'
}
return (
<div className={cn} key={index}>
<span>{v.user}:</span>
<span>{v.message}</span>
</div> )
})
}
</div>
</div>
</div> );
}
}
export default SocketDemo;
Copy the code
Finally add SRC /iosocket-demo.css
body{
background: #008DB7;
font-family: 'Microsoft YaHei UI';
}
.loginDiv{
text-align: center;
margin: 150px auto 0;
width: 250px;
}
.loginDiv input[type='text']{
display: inline-block;
box-sizing: border-box;
border-radius: 5px;
padding-left: 5px;
border: none;
width: 250px;
height: 35px;
line-height: 35px;
}
.loginDiv button{
display: inline-block;
box-sizing: border-box;
border-radius: 5px;
padding-left: 5px;
border: none;
width: 250px;
height: 35px;
line-height: 35px;
margin-top: 10px;
background: #0067A2;
color: #ffffff;
}
.talkDiv{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.talkDiv .operatingDiv{
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 40px;
display: flex;
}
.talkDiv .operatingDiv input[type='text']{
flex: 1;
height: 40px;
line-height: 40px;
box-sizing: border-box;
padding-left: 10px;
}
.talkDiv .operatingDiv button{
display: inline-block;
box-sizing: border-box;
border-radius: 5px;
border: none;
width: 250px;
height: 40px;
line-height: 40px;
background: #0067A2;
color: #ffffff;
}
.talkDiv .showDiv{
position: fixed;
bottom: 40px;
left: 0;
right: 0;
top: 0;
font-size: 16px;
color: #ffffff;
overflow: auto;
}
.talkDiv .showDiv .titleInfo{
padding: 10px;
color: yellow;
font-size: 20px;
}
.talkDiv .showDiv .showInfo{
padding: 10px;
}
Copy the code
Add a command line to package.json
"scripts": {
"start": "node scripts/start.js"."build": "node scripts/build.js"."server": "nodemon server/index.js"
},
Copy the code
- Run the background YARN Server
- Run the front yarn Start command
Start the program
The source address
Gitee.com/melissayan/…
Preview the address
http://106.12.186.15:9005