为啥 useEffect() 不更新新消息上的消息对象?

Posted

技术标签:

【中文标题】为啥 useEffect() 不更新新消息上的消息对象?【英文标题】:Why does useEffect() not updating messages object on new message?为什么 useEffect() 不更新新消息上的消息对象? 【发布时间】:2021-07-01 11:13:18 【问题描述】:

我是新手,我正在关注 socket.io 的实时聊天教程。用户加入房间,然后会出现一个文本框。当用户键入消息并发送它时,messages 对象必须存储该消息。 message 正在从服务器发送,但在客户端 message 没有更新为新消息。 useEffect 不起作用吗?或者我怎样才能更新数组?

Chat.js

import queryString from 'query-string';
import io from 'socket.io-client';

let socket;

const Chat = ( location ) => 
    const [name, setName] = useState('');
    const [room, setRoom] = useState('');
    const [message, setMessage] = useState('');
    const [messages, setMessages] = useState([]);
    const ENDPOINT = 'localhost:5000';

    useEffect(() => 
        const  name, room  = queryString.parse(location.search);

        socket = io(ENDPOINT);

        setName(name);
        setRoom(room);

        socket.emit('join',  name, room , () => 

        );

        return () => 
            socket.disconnect();

        
    ,[ENDPOINT, location.search]);

    useEffect(() => 
        socket.on('message', (message) => 
            setMessages([...messages, message]);
        );
    , [messages]);

    const sendMessage = (event) => 
        event.preventDefault();

        if (message) 
            socket.emit('sendMessage', message, () => setMessage(''));
        

        console.log(message, messages);
    

    return (
        <div className="outerContainer">
            <div className="container">
                <input
                    value=message
                    onChange=event => setMessage(event.target.value)
                    onKeyPress=event => event.key === 'Enter' ? sendMessage(event) : null
                />
            </div>
        </div>
    );
;

export default Chat; 

index.js

const socketio = require('socket.io');
const http = require('http');

const  addUser, removeUser, getUser, getUsersInRoom  = require('./users');

const PORT = process.env.PORT || 5000;

const router = require('./router');

const app = express();
const server = http.createServer(app);
const io = socketio(server, 
    cors: 
        origin: "http://localhost:3000",
        methods: ["GET", "POST"]
    ,
);

io.on('connection', (socket) => 
    socket.on('join', ( name, room , callback) => 
        const  error, user = addUser( id: socket.id, name, room);

        if (error) 
            return callback(error);
        

        socket.emit('message',  user: 'admin', text: `$user.name, welcome to the room $user.room`);
        socket.broadcast.to(user.room).emit('message',  user: 'admin', text: `$user.name, has joined`);

        socket.join( user, room);

        callback();
    );

    socket.on('sendMessage', (message, callback) => 
        const user = getUser(socket.id);

        io.to(user.room).emit('message',  user: user.name, text: message);

        callback();
    );

    socket.on('disconnect', () => 
        console.log('User had left!!!');
    );
);

app.use(router);

server.listen(PORT, () => console.log(`Server has started $PORT`));```

【问题讨论】:

【参考方案1】:

问题是您正在更新 useEffect() 中的消息状态,其中 messages 作为依赖项之一。你可以通过将回调传递给setMessages() 来解决这个问题,如下所示:

setMessages(prevMessages => [...prevMessages, message])

并从依赖数组中移除 messages 依赖。

【讨论】:

仍然没有更新 messages 数组。我更新了useEffect() 这样useEffect(() =&gt; socket.on('message', (message) =&gt; setMessages((messages) =&gt; [...messages, message]); ); ); 你能在'message'事件中添加一个console.log()吗? 我尝试做console.log(message),它返回消息但是socket.on('message', (message) =&gt; setMessages((messages) =&gt; [...messages, message]); );没有更新messages数组 messages 数组会在组件下次渲染时更新。尝试控制台在 useEffect 挂钩之外记录消息数组 还是一样。我会给你我的回购链接,你能检查一下Githubrepo

以上是关于为啥 useEffect() 不更新新消息上的消息对象?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我使用 `useRef` 创建的我的参考会产生此错误消息?

微信支付为啥没有消息提醒?

为啥 useState 钩子在 useEffect() 中使用循环时不更新

React:如何通过 Firestore onSnapshot 和 useEffect 使用最新状态?

next.js socket.io 使用效果不更新套接字消息

状态在 useEffect 中没有更新,为啥?