WebSocket的实现(react+socket.io)

文章展示了如何利用socket.io在Node.js后端和React前端建立实时通信。通过在后端设置服务器监听连接、处理用户数据和消息传递,以及在前端创建socket连接并发送、接收消息,实现了聊天功能。同时,文章提到了依赖管理和端口设置。
摘要由CSDN通过智能技术生成

后端下载依赖:

yarn  add  socket.io  // 采用socket.io进行实时通信

 在router/index.js中配置连接

var express = require('express');
var router = express.Router();
const http = require('http');
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketIO(server, {
    cors: {
        origin: '*'
    }
});


// 在线用户列表
let userList = []

// 用户连接
io.on('connection', (socket) => {
    console.log('用户连接成功');
    let userSocketId = socket.id;
    // 初始化 数据
    socket.on('userData', (data) => {
        let idx = userList.findIndex(item => {
            return item._id === data._id
        })
        if (idx === -1) {
            userList.push(data)
        }
        io.emit('online', userList)

        // 设置当前用户的userid
        socket.emit('userid', { user: data, userId: userSocketId, })
    });



    // 接收客户端发送的消息
    socket.on('message', ({ partner, user, message }) => {
        socket.to(partner.userID).emit('sendOne', message)
    })

    // 用户离开
    socket.on('disconnect', () => {
        console.log('用户离开');
    });

    // 离开时 获取到的 用户信息
    socket.on('leave', (data) => {
        let idx = userList.findIndex(item => item._id === data._id);
        // 离开时 删除在线人员
        userList.splice(idx, 1)
        // 离开时 更新在线人员
        io.emit('online', userList)
    })
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

前端依赖

yarn  add  socket.io-client   // 前端采用 socket.io-client 来实现实时通信

import React, { useEffect, useState } from 'react'
import '../css/DetailChat.scss'
import { useLocation, useNavigate } from 'react-router-dom'
import { Toast, NavBar, Input, Button } from 'react-vant';
import { WapNav } from '@react-vant/icons';
import io from 'socket.io-client';
import axios from 'axios';


export default function DetailChat() {
    const socket = io('http://localhost:3000'); // 指定服务器的URL
    let location = useLocation()
    const Navigate = useNavigate()
    // 对象数据
    let partner = location.state;
    // 当前用户数据
    let userData = JSON.parse(sessionStorage.getItem('user')) || []
    // 定义输入框的信息
    const [iptValue, setIptValue] = useState('')
    // 保存聊天记录
    const [record, setRecord] = useState([])

    // 发送消息
    const send = async () => {
        let { data } = await axios.get(`http://localhost:3002/getPartner?id=${partner._id}&uid=${userData._id}&message=${iptValue}`)

        if (data.code === 200) {
            socket.emit('message', { partner: data.data[0], user: data.data[1], message: iptValue })
            setIptValue('')
            getrecord()
        }
    }
    // 用户连接
    useEffect(() => {
        getrecord()
        socket.on('connect', () => {
            // 发送用户信息到服务器
            socket.emit('userData', userData);

            // 设置userid
            socket.on('userid', data => {
                saveData(data)
            })
        })

        // 接收数据
        socket.on('sendOne', (data) => {
            getrecord()
        })

        return () => {
            socket.emit('leave', userData) // 离开时传递 用户信息
            socket.disconnect(); // 组件卸载时断开连接
        };
    }, []);

    // 监听新消息保持在最底部--- 获取最后一条消息
    useEffect(() => {
        let lasrChild = document.querySelector('.detailChat-message').lastElementChild
        if (lasrChild) {
            lasrChild.scrollIntoView(false)
        }
    }, [record])

    // 初始化  --- 保存用户的连接 id
    const saveData = async (user) => {
        await axios.post('http://localhost:3002/saveData', user)
    }

    // 获取聊天记录
    const getrecord = async () => {
        let { data } = await axios.get(`http://localhost:3002/getrecord?user1=${partner._id}&user2=${userData._id}`)
        setRecord(data.data)
    }

    // 返回
    const goback = () => {
        Navigate('/chat')
    }
    return (
        <div className='detailChat'>

            {/* 个人聊天 -- 顶部区域 */}
            <div className='detailChat-top'>
                <NavBar
                    title={partner.userName}
                    // leftText={  }
                    rightText={<WapNav />}
                    onClickLeft={goback}
                    onClickRight={() => Toast('按钮')}
                />
            </div>
            {/* 聊天记录显示区域 */}
            <div className='detailChat-message'>
                {
                    record.map((item, index) => {
                        return (
                            <div className='detailChat-item' key={index}>
                                {
                                    item.sendUser === userData._id ?
                                        <div style={{ textAlign: 'right',paddingRight: '.5rem'}}>
                                            <div className='detailChat-item-right'>{item.message}</div>
                                            <img src={userData.headPortrait} alt="" />

                                        </div>
                                        :
                                        <div style={{ textAlign: 'left', paddingLeft: '.5rem' }}>
                                            <img src={partner.headPortrait} alt="" />
                                            <div className='detailChat-item-left'>{item.message}</div>
                                        </div>
                                }
                            </div>
                        )
                    })
                }
            </div>

            {/* 个人聊天 -- 底部输入区域 */}
            <div className='detailChat-bottom'>
                <Input
                    value={iptValue}
                    onChange={(value) => setIptValue(value)}
                    onKeyDown={(e) => e.keyCode === 13 ? send() : ''}
                    prefix="💁"
                    suffix={<Button size="small" type="primary" onClick={send} >发送</Button>}
                    placeholder="请输入发送的内容"
                />
            </div>
        </div>
    )
}

实现效果展示:

WebSocket的实现

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值