我试图用socket.io和react构建一个基本的聊天应用程序,但是遇到了一个奇怪的问题。 这款应用程序的工作方式就像预期的那样,可以处理前5条消息,但之后的第6条消息需要很长时间才能加载,而且之前的一些消息通常不会显示在聊天框中。 如果有人能帮忙我会很高兴的。 下面是我的后端代码:
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
io.on('connection', socket => {
socket.on('message', ({ name, message }) => {
io.emit('message', { name, message });
console.log(message);
console.log(name);
});
});
http.listen(4000, function () {
console.log('listening on port 4000');
});
下面是我在app.js中的代码:
import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';
const App = props => {
const socket = io.connect('http://localhost:4000');
const [details, setDetails] = useState({ name: '', message: '' });
const [chat, setChat] = useState([]);
useEffect(() => {
socket.on('message', ({ name, message }) => {
setChat([...chat, { name, message }]); //same as {name:name,message:message}
});
});
const onMessageSubmit = e => {
e.preventDefault();
const { name, message } = details;
socket.emit('message', { name, message });
setDetails({ name, message: '' });
};
return (
<div>
<form onSubmit={onMessageSubmit}>
<input
type='text'
value={details.name}
onChange={e => setDetails({ ...details, name: e.target.value })}
/>
<input
type='text'
value={details.message}
onChange={e => setDetails({ ...details, message: e.target.value })}
/>
<button>Send</button>
</form>
<ul>
{chat &&
chat.map((chat, index) => (
<li key={index}>
{chat.name}:{chat.message}
</li>
))}
</ul>
</div>
);
};
export default App;
那是因为每次,您更新状态,useEffect回调运行,基本上您一次又一次地订阅message
。
在几次迭代之后,您就会有多个订阅试图更新相同的状态。 而且由于setstate
的异步特性,您会看到奇怪的行为。
您只需要订阅一次,可以通过将空依赖项参数传递给UseEffect
来实现这一点,这将使其工作方式与ComponentDidMount
类似
useEffect(() => {
socket.on('message', ({ name, message }) => {
setChat([...chat, { name, message }]);
});
}, []);
您可能希望在卸载组件时cleanup
。 请看一下官方文件。