Nextjs 状态重置每个套接字事件发生

Nextjs state reset every socket event occur

我尝试制作将集成到我的 Nextjs 应用程序中的聊天功能。我遵循了文档,但聊天日志重置了每个发生的套接字事件。 代码如下:

import { useState, useEffect } from 'react'
import io from 'socket.io-client'

export default function Chat() {

    const [chats, setChats] = useState([])
    let socket = io(':3000')
    
    useEffect(() => {

        socket.on('chat message', function(msg) {
    
            console.log(chats)
            setChats([
                ...chats,
                msg
            ]) 
            window.scrollTo(0, document.body.scrollHeight);  
        }.bind(this));

    }, [])

    const submitHandler = (e) => {
        e.preventDefault()
        let input = document.getElementById('input');
        if (input.value) {      
            socket.emit('chat message client', input.value);
            input.value = '';    
        }
    }
    
    console.log(chats)

    return (
        <div className='container mt-5 pt-5'>
            <ul id="messages">
                {
                    chats.map(chat => <li>{chat}</li>)
                }
            </ul>    
            <form id="form" onSubmit={submitHandler}>      
                <input id="input" autocomplete="off" />
                <button>Send</button>    
            </form>
        </div>
    )
}

快速聊天服务器:

const express = require('express');
const cors = require("cors");
const socket = require("socket.io");

const app = express();

app.use(cors())

const server = app.listen(3000, () => {
    console.log('listening on *:3000');
});

const io = socket(server, {
    cors: {
        origin: "http://localhost:5000",
        methods: ["GET", "POST"],
        allowedHeaders: ["my-custom-header"],
        credentials: true
    }
});

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', (socket) => {
    console.log("connected")
    socket.on('chat message client', (msg) => {
        console.log('message: ' + msg);
        io.emit('chat message', msg)
    });
});

state 'chats' 仅包含最新消息,因为聊天每次都设置为空数组。

我尝试更改 useEffect 挂钩运行每次聊天更改如下:

useEffect(() => {

        socket.off('chat message').on('chat message', function(msg) {
    
            console.log(chats)
            setChats([
                ...chats,
                msg
            ]) 
            window.scrollTo(0, document.body.scrollHeight);  
        }.bind(this));

    }, [chats])

它工作了大约 10 次,但之后它显示 web socket connection failed 错误 似乎聊天功能每次都建立套接字连接。 (这就是为什么我 尝试添加 .off('chat message'),但似乎无法正常工作)。 我不知道它是如何修复的。 请告诉我任何建议。

出现此问题的原因可能是您在使用“setChat”函数设置新状态时在每次渲染时初始化套接字变量。

尝试将变量移到组件外部,例如:

let socket = null

export default function Chat() {

const [chats, setChats] = useState([])    

useEffect(() => {
    if(socket == null)// Ensure that this variable is not initialized
        socket = io(':3000')
    socket.on('chat message', function(msg) {

        console.log(chats)
        setChats([
            ...chats,
            msg
        ]) 
        window.scrollTo(0, document.body.scrollHeight);  
    }.bind(this));

    }, [])
}

我对@humam ayad 的代码做了一些调整:

let socket = null

export default function Chat() {

    const [chats, setChats] = useState([])
    
    useEffect(() => {

        if(socket == null) socket = io(':3000')

        socket.off('chat message').on('chat message', function(msg) {
    
            console.log(chats)
            setChats([
                ...chats,
                msg
            ]) 
            window.scrollTo(0, document.body.scrollHeight);  
        }.bind(this));

    }, [chats])