Socket.io front and back -Fend Unicom to create a conversation

Node.js provides an efficient server-side workbench, but because the browser side has different HTML5 support to compare browsers, provide a great real-time user experience, and provide programmers with client-server consistency. programming expertise, hence Socket.io was born. Socket.io encapsulates WebSocket, polling mechanism and other real-time communication methods into public interfaces, and executes the code corresponding to these real-time mechanisms on the server.

Socket.io implements communication mechanisms based on real events. The goal is to allow different browsers and mobile devices to implement the actual features of the applications and obliterate the different transmission mechanisms. Socket.io is a cross platform. A variety of connection methods are automatically switched. IM development is convenient and can be well combined with the traditional request method provided by ExpressJS.


Code running environment

end of introduction end of the road Database
react pass MongoDB

basic dependencies

"express": "^4.17.1",
"socket.io": "^3.1.0",
"socket.io-client": "^3.1.0",

end of the road

(The chat room is started by the user, so when creating the chat form, the user form must also be set)

1. server. js

(project entry file, Socket.io configuration)

const express = require('express')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const model = require('./model')
const Chat = model.getModel('chat')
const app = express()

const server = require('http').Server(app)


const io = require('socket.io')(server, { cors: true })


io.on('connection', function(socket) {
  
  socket.on('sendmsg', function(data) {
    const { from, to, msg } = data
    
    const chatid = [from, to].sort().join('_')
    
    Chat.create({chatid, from, to, content: msg}, function(err, doc) {
    
      io.emit('recvmsg', Object.assign({}, doc._doc))
    })
  })
})

const userRouter = require('./user')

app.use(cookieParser())
app.use(bodyParser.json())
app.use('/user', userRouter)
server.listen(9093, function() {
  console.log('server port is 9093')
})

2.model.js

const mongoose = require('mongoose')
const DB_URL = 'mongodb://localhost:27017/goodwork'
mongoose.connect(DB_URL)

const models = {
	user:{
		'user':{type:String, 'require':true},
		'pwd':{type:String, 'require':true},
		'type':{'type':String, 'require':true},
		
		'avatar':{'type':String},
		
		'desc':{'type':String},
		'title':{'type':String},
		'company':{'type':String},
		'money':{'type':String}
	},
	chat:{
		'chatid': {type: String, require: true},
		'from': {type: String, require: true},
		'to': {type: String, require: true},
		'read': {type: Boolean, default: false},
		'content': {type: String, require: true, deafult: ''},
		'create_time': {type: Number, deafult: new Date().getTime()}
	}
}

for(let m in models){
	mongoose.model(m, new mongoose.Schema(models[m]))
}

module.exports = {
	getModel:function(name){
		return mongoose.model(name)
	}
}

3. user. js

(routing files, writing message lists and unread lists)

const { json } = require('body-parser')
const express = require('express')
const utils = require('utility')
const Router = express.Router()
const model = require('./model')
const User = model.getModel('user')
const Chat = model.getModel('chat')

const _filter = { 'pwd': 0, '__v': 0 }


Router.get('/getmsglist', function(req, res) {
  
  const user = req.cookies.userid
  User.find({}, function(e, userdoc) {
    let users = {}
    userdoc.forEach(v => {
      users[v._id] = { name: v.user, avatar: v.avatar }
    })
    Chat.find({'$or': [{ from: user}, { to: user }]}, function(err, doc) {
      if (!err) {
        return res.json({
          code: 0,
          msgs: doc,
          users: users
        })
      }
    })
  })
})

Router.post('/readmsg', function (req, res) {
  const userid = req.cookies.userid
  const { from } = req.body
  console.log(userid, from)
  Chat.updateMany(
    { from, to: userid },
    { '$set': { read: true } },
    { 'multi': true },
    function (err, doc) {
      console.log(doc)
      if (!err) {
        return res.json({
          code: 0,
          num: doc.nModified
        })
      }
      return res.json({
        code: 1,
        msg: 'ошибка'
      })
    })
})

module.exports = Router

end of introduction

(Writing in front is more complicated, it involves jumping between each page and processing data between Redux. I can’t describe all the details clearly here, please forgive me)

The front-end page uses Redux to manage the data

1. redux/chat.redux.js

import axios from 'axios'
import io from 'socket.io-client'
const socket = io('ws://localhost:9093')


const MSG_LIST = 'MSG_LIST'

const MSG_RECV = 'MSG_RECV'

const MSG_READ = 'MSG_READ'

const initState = {
  chatmsg: [],
  users: {},
  unread: 0
}

export function chat(state = initState, action) {
  switch (action.type) {
  
    case MSG_LIST:
      return { ...state,
        users: action.payload.users,
        chatmsg: action.payload.msgs,
        unread: action.payload.msgs.filter(v => !v.read && v.to === action.payload.userid).length 
      }
     
    case MSG_RECV:
      const n = action.payload.to === action.userid ? 1 : 0
      return {
        ...state,
        chatmsg: [...state.chatmsg, action.payload],
        unread: state.unread + n
      }
    
    case MSG_READ:
      const { from } = action.payload
      return {
        ...state, 
        chatmsg: state.chatmsg.map(v => ({...v, read: from === v.from ? true : v.read})),
        unread: state.unread.num ? state.unread.num : 0}
    default:
      return state
  }
}

function msgRecv(msg, userid) {
  return { userid, type: MSG_RECV, payload: msg }
}


export function recvMsg() {
  return (dispatch, getState) => {
  
    socket.on('recvmsg', function(data) {
      const userid = getState().user._id
      dispatch(msgRecv(data, userid))
    })
  }
}

function msgList(msgs, users, userid) {
  return { type: MSG_LIST, payload: {msgs, users, userid} }
}


export function getMsgList() {
  return (dispatch, getState) => {
    axios.get('/user/getmsglist').then(res => {
      console.log(res)
      if (res.status === 200 && res.data.code === 0) {
        const userid = getState().user._id
        dispatch(msgList(res.data.msgs, res.data.users, userid))
      }
    })
  }
}


export function sendMsg({ from, to, msg }) {
  return dispatch => {
    socket.emit('sendmsg', { from, to, msg })
  }
}

function msgRead({ from, userid, num }) {
  return { type: MSG_READ, payload: { from, userid, num } }
}

export function readMsg(from) {
  return (dispatch, getState) => {
    axios.post('/user/readmsg', {from}).then(res => {
      const userid = getState().user._id
      if (res.status === 200 && res.data.code === 0) {
        const num = res.data.num
        dispatch(msgRead({ userid, from, num }))
      }
    })
  }
}

2. chat. js

import { Grid, Icon, InputItem, List, NavBar } from 'antd-mobile';
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { getMsgList, sendMsg, recvMsg, readMsg } from '../../redux/chat.redux'
import { getChatId } from '../../util'

@connect(
  state => state,
  { getMsgList, sendMsg, recvMsg, readMsg }
)
class Chat extends Component {
  constructor(props) {
    super(props);
    this.state = {
      text: '',
      msg: []
    }
  }
  componentDidMount() {
  
    if (!this.props.chat.chatmsg.length) {
      this.props.getMsgList()
      this.props.recvMsg()
    }
  }
  
  componentWillUnmount() {
    const to = this.props.match.params.user
    this.props.readMsg(to)
  }
  fixCarousel() {
    setTimeout(function () {
      window.dispatchEvent(new Event('resize'))
    }, 0)
  }
  handleSubmit() {
    
    const from = this.props.user._id
    
    const to = this.props.match.params.user
    
    const msg = this.state.text
    this.props.sendMsg({ from, to, msg })
    this.setState({
      text: '',
      showEmoji: false
    })
  }
  render() {
    const emoji = '😀 😁 😂 😍 😘 😝 😬 🤮 🤟 🤏 👌 🤜 🙏'
      .split(' ')
      .filter(v => v)
      .map(v => ({ text: v }))

    const userid = this.props.match.params.user
    const Item = List.Item
    const users = this.props.chat.users
    if (!users[userid]) {
      return null
    }
    const chatid = getChatId(userid, this.props.user._id)
    const chatmsgs = this.props.chat.chatmsg.filter(v => v.chatid === chatid)
    return (
      <div id="chat-page">
        <div style={{ position: "fixed", zIndex: 999, width: '100%' }}>
          <NavBar
            mode="dark"
            icon={<Icon type="left"></Icon>}
            onLeftClick={() => {
              this.props.history.goBack()
            }}
          >
            {users[userid].name}
          </NavBar>
        </div>
        {}
        {chatmsgs.map(v => {
          const avatar = require(`../img/${users[v.from].avatar}.png`).default
          return v.from === userid ? (
            <List key={v._id}>
              <Item
                thumb={avatar}
                multipleLine={true}
                wrap={true}
                platform="android"
              >{v.content}</Item>
            </List>
          ) : (
              <List key={v._id}>
                <Item
                  multipleLine={true}
                  wrap={true}
                  platform="android"
                  extra={<img src={avatar} alt="" />
                  }
                  className="chat-me"
                >{v.content}</Item>
              </List>
            )
        })}
        {}
        <div className="stick-fooetr">
          <List>
            <InputItem
              placeholder='Пожалуйста, входите'
              value={this.state.text}
              onChange={v => {
                this.setState({ text: v })
              }}
              extra={
                <div>
                  <span
                    style={{ marginRight: 15 }}
                    onClick={() => {
                      this.setState({
                        showEmoji: !this.state.showEmoji
                      })
                      this.fixCarousel()
                    }}
                  >😀</span>
                  <span onClick={() => this.handleSubmit()}>Отправить</span>
                </div>
              }
            ></InputItem>
            {this.state.showEmoji ? <Grid
              data={emoji}
              columnNum={9}
              carouselMaxRow={2}
              isCarousel={true}
              onClick={el => {
                this.setState({
                  text: this.state.text + el.text
                })
                console.log(el)
              }}
            /> : null}
          </List>
        </div>
      </div>
    )
  }
}

export default Chat


The concrete code can access the authority of gitee
You can also look at the author’s public account: Daming Lady, (Answer: Socket.io) Get tutorials

Leave a Comment