Javascript 每发送一条消息,useEffect会运行两倍的时间

Javascript 每发送一条消息,useEffect会运行两倍的时间,javascript,node.js,reactjs,express,socket.io,Javascript,Node.js,Reactjs,Express,Socket.io,我正在用react、express和socket.io构建一个简单的聊天应用程序 我在接收来自后端服务器的消息时遇到了问题。 每次用户收到一些消息时,useffect的运行速度大约是以前的两倍,因此在收到5或6条消息后,应用程序的启动速度确实会减慢 useEffect(() => { socket.on('mes', (data) => { setChat([...chat, data]); }); }, [chat]); 您知道如何让它在用户每次收

我正在用react、express和socket.io构建一个简单的聊天应用程序 我在接收来自后端服务器的消息时遇到了问题。 每次用户收到一些消息时,
useffect
的运行速度大约是以前的两倍,因此在收到5或6条消息后,应用程序的启动速度确实会减慢

useEffect(() => {
    socket.on('mes', (data) => {
      setChat([...chat, data]);
    });
  }, [chat]);
您知道如何让它在用户每次收到消息时只运行一次吗

全部代码

import Chat from '../Chat/chat';
import queryString from 'query-string';
let socket;
const ChatRoom = ({ location }) => {
  const [name, setName] = useState('');
  const [room, setRoom] = useState('');

  const [message, setMessage] = useState('');
  const [chat, setChat] = useState([]);
  const ENDPOINT = 'http://localhost:4001/';

  useEffect(() => {
    const { name, room } = queryString.parse(location.search);
    setName(name);
    setRoom(room);

    socket = socketIOClient(ENDPOINT);
    socket.emit('join', { name, room });

    return () => {
      socket.emit('disconnect');
      socket.disconnect();
    };
  }, [ENDPOINT, location.search]);

  const click = (e) => {
    e.preventDefault();
    socket.emit('message', message);
    setMessage('');    
  };
  useEffect(() => {
    socket.on('mes', (data) => {
      setChat([...chat, data]);
    });
  }, [chat]);

  return (
    <div className="ChatRoom-Container">
      {chat.map((mes, index) => {
        return <Chat text={mes.text} user={mes.user} key={index}></Chat>;
      })}
      <input
        value={message}
        className="ChatRoom-Input"
        onChange={(e) => setMessage(e.target.value)}
        onKeyDown={(e) => {
          return e.key === 'Enter' ? click(e) : null;
        }}
      ></input>
    </div>
  );
};

export default ChatRoom;
从“../Chat/Chat”导入聊天;
从“查询字符串”导入查询字符串;
让插座;
const聊天室=({location})=>{
const[name,setName]=useState(“”);
常数[房间,设置室]=使用状态(“”);
const[message,setMessage]=useState(“”);
const[chat,setChat]=useState([]);
常数端点http://localhost:4001/';
useffect(()=>{
const{name,room}=queryString.parse(location.search);
集合名(名称);
休息室;
套接字=socketIOClient(端点);
emit('join',{name,room});
return()=>{
socket.emit('disconnect');
socket.disconnect();
};
},[ENDPOINT,location.search]);
常量单击=(e)=>{
e、 预防默认值();
发出('message',message);
setMessage(“”);
};
useffect(()=>{
socket.on('mes',(数据)=>{
setChat([…聊天,数据]);
});
},[聊天];
返回(
{chat.map((mes,索引)=>{
返回;
})}
setMessage(e.target.value)}
onKeyDown={(e)=>{
返回e.key==“回车”?点击(e):空;
}}
>
);
};
导出默认聊天室;
使用而不是
setChat(value)
,这样您就不必从闭包中引用以前的值:

useEffect(() => {
  socket.on('mes', (data) => {
    setChat(prev => [...prev, data]);
  });
}, []);
在依赖项数组中,chat变量是一个依赖项。 根据规则,当chat的值更改时,效果将运行。
因此,在您调用一次
setChat()
后,它会更改chat的值,并因此再次运行效果。这就是为什么你的效果被调用了两次。

谢谢,伙计,我不明白为什么它有效,但它确实有效。@KlopoCz另一个答案很好地解释了为什么另一种方法无效。本质上,
socket.on('mes',…)
是在每次更改
chat
变量时进行计算的,而不是在安装组件时仅计算一次。
useEffect(() => {
    socket.on('mes', (data) => {
      setChat([...chat, data]);
    });
  }, [chat]);