欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Socket.io +react + egg聊天室

程序员文章站 2022-07-10 21:22:01
...

技术栈:
前端:react
后端:egg
通信手段:socket.io

官方API: https://socket.io/get-started/chat/
socket.io的工作流程:
客户端 =》服务端 =》客户端
socket.io: 通俗易懂的来讲,比如说你喜欢隔壁班的李小花,你想一下让全学校的人都知道,怎么办?
当让是去广播站,然后让他帮你广播一下,然后全学校的人收到消息,哦,张全蛋喜欢李小花;

下面简单的实现一个在线果聊。。。
效果图如下:
Socket.io +react + egg聊天室

Socket.io +react + egg聊天室

Socket.io +react + egg聊天室

Socket.io +react + egg聊天室

首先进入登录页,输入用户名进入聊天室,如果用户不存在,那么添加到数据库,然后进入聊天室,如果用户存在,那么提示用户已存在,然后重新输入用户名。

react: src/view/ChatRoom/index.js

import React, { Component , Fragment} from 'react';
import io from 'socket.io-client';
import './style.css';
import Axios from 'aaa@qq.com@axios';
class ChatRoom extends Component {
    constructor(props) {
        super(props);
        this.state = { 
            userNameIpt:'',//login 的用户名
            userSay:'',//聊天室里的input
            hide:true,//隐藏聊天室
            socket:io('http://192.168.31.3:3333'),//配置socket
            userName:'',//进入聊天室之后保存的用户名
            wordList:[]//聊天记录
         }
    }
    render() { 
        let {userNameIpt,userSay,hide,wordList,userName} = this.state;
        return ( 
            <div className="chatRoom">
                <input type='text' 
                       value={userNameIpt} 
                       onChange={this.changeIpt.bind(this)} 
                       name="userNameIpt"
                       onKeyDown={this.setUser.bind(this)}
                       placeholder="输入用户名,按下回车"
                       />
                
                <div className={hide?'chatMask hide':'chatMask'}>
                    <header>聊天室</header>
                    <ul>
                        {
                            wordList && wordList.map((item,index)=>{
                                return (
                                    <li key={index}>
                                        <b>{item.userName}</b>
                                        <span>{item.userSay}</span>
                                    </li>
                                )
                            })
                        }
                    </ul>
                    <footer>
                        <input type="text" value={userSay} onChange={this.changeIpt.bind(this)} name="userSay"/>
                        <button onClick={this.sendUserSay.bind(this)}>发送</button>
                    </footer>
                </div>
            </div>
         );
    }
    changeIpt(e){
        this.setState({ [e.target.name]:e.target.value  });
    }
    setUser(e){
        let {userNameIpt,userName} = this.state;
        if(e.keyCode===13){
            //发送注册请求
            Axios
                .post('/login',{
                    userNameIpt
                })
                .then(res=>{

                    if(res.data.code===0){
                        //用户存在
                        
                    }else{
                        //用户不存在,成功注册
                        console.log(res.data)

                        this.setState({ userName:res.data.flag.userName , hide:false });
                        //注册成功保存用户名 然后 做显示聊天室
                    }
                    alert(res.data.msg)
                })


            // this.setState({ hide:false  });
        }
    }
    sendUserSay(){
        let {socket,userSay,userName} = this.state;
        socket.emit('message',{
            userSay,
            userName
        })
        this.setState({ userSay:''  });
    }
    componentDidMount(){
        let {socket,wordList} = this.state;
        socket.on('showMsg',(data)=>{
            console.log(data)
            wordList.push(data)
            this.setState({ wordList  });
        })
    }
}
 
export default ChatRoom;

socket: socket/app.js

var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);

io.on('connection', function(socket){
  console.log('一个用户连接了');
  socket.on('message',function (data) { 
      let {userSay,userName} = data;
      socket.emit('showMsg',{userSay,userName})//对用户自己的
      socket.broadcast.emit('showMsg',{userSay,userName})//广播的
   })
});

http.listen(3333, function(){
  console.log('listening on *:3333');
});

egg: egg/app/router.js

'use strict';

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => {
  const { router, controller } = app;
  router.post('/login', controller.login.index)
};

egg:egg/app/controller/login.js

'use strict';

const Controller = require('egg').Controller;

class LoginController extends Controller {
  async index() {
    const { ctx } = this;
    let userNameIpt = ctx.request.body.userNameIpt;
    let result = await ctx.service.login.set(userNameIpt);
    ctx.body = result;
  }
}

module.exports = LoginController;

egg: egg/app/service/login.js

module.exports = app => {
    const uid = require('uid')
  class LoginService extends app.Service {
        async set(userNameIpt) {
            
            
            let flag = await this.app.mysql.get('userList',{
                userName:userNameIpt
            })
            if(flag){
                return {
                    code:0,
                    msg:'用户存在'
                }
            }else{
                let result = await this.app.mysql.insert('userList',{
                    userName:userNameIpt,
                    id:uid(10)
                })

                let flag = await this.app.mysql.get('userList',{
                    userName:userNameIpt
                })

                return {
                    code:1,
                    msg:'注册成功',
                    flag
                }
            }

        }
  }
  return LoginService
}

中途遇到的几个坑:

  1. 服务端渲染 需要在index.html里引入 script 标签 socket.io.js
  2. 在Vue or React 里,客户端需要执行 cnpm install socket.io --save
  3. 引入后,配置时候需要注意 io(’‘http://localhost:3333") 需要别人访问的时候改成具体的 io(’'http://192.168.2.11:3333") ;