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