如何防止React重新呈现功能组件中的每个功能

时间:2020-07-21 17:09:50

标签: reactjs mongodb socket.io react-state-management

我有两个用户通过加入同一个Socket.io房间而获得私人消息,该房间基于从发送者和接收者ID创建的房间。每次我创建一条消息时,由于状态更改,由于Socket.io发出事件重新渲染,客户端都会重新加入房间,并且将RoomId记录在控制台中。结果,当消息加入同一个会议室时,消息不会通过多个聊天实例进行传输。

const ChatApp = () => {
  const [messages, setMessages] = React.useState([]);
  const userId = useSelector(state => state.profile.profile._id);
  const senderFullName = useSelector(state => state.auth.user.fullname);
  const authId = useSelector(state => state.auth.user._id);
  const roomId = [authId, userId].sort().join('-');
  const ioClient = io.connect("http://localhost:5000"); 

    ioClient.emit('join', {roomid: roomId});
    ioClient.emit('connected', {roomid: roomId} );
    ioClient.on('message', (msg) => {
      const messageObject = {
        username: msg.from,
        message : msg.body,
        timestamp: msg.timestamp
      };
      addMessage(messageObject);
    });

  const addMessage = (message) => {
   const messagess = [...messages];
   messagess.push(message); 
   setMessages(messagess);
   console.log(messagess);   
   }

   const sendHandler = (message) => {
    var res = moment().format('MM/DD/YYYY h:mm a').toString();

    // Emit the message to the server
    ioClient.emit('server:message', {from: senderFullName, body: message, timestamp: res });
   }
   
     return (

<div className="landing">
<Container>
 <Row className="mt-5">
   <Col md={{ span: 8, offset: 2 }}>

     <Card style={{ height: "36rem" }} border="dark">
       <Messages msgs={messages} />
       <Card.Footer>
       <ChatInput onSend={sendHandler}>
         </ChatInput>
       </Card.Footer>
     </Card>
   </Col>
 </Row>
</Container>
</div>
   )
 };

服务器中使用的api代码

    io.sockets.on("connection",function(socket){
        // Everytime a client logs in, display a connected message
        console.log("Server-Client Connected!");

        socket.on('join', function(data) {

           socket.join(data.roomid, () => {
               //this room id is being console logged every time i send a message
               console.log(data.roomid);
           }); 

        });    

         socket.on('connected', function(data) {    
            //load all messages
            console.log('message received');
            (async () => {
                try {
                    console.log('searching for Schema');
            const conversation = await Conversation.find({roomId: data.roomid}).populate('messages').lean().exec();
            const mess = conversation.map(); 
            console.log(mess);   
            console.log('Schema found');    
            }
               catch (error) {
                   console.log('Schema being created');
                Conversation.create({roomId: data.roomid});
               }
        })();

    });

        socket.on('server:message', data => {
 
            socket.emit('message', {from: data.from, body: data.body, timestamp: data.timestamp});
            console.log(data.body);
            Message.create({from: data.from, body: data.body});

                
        })     
    });

1 个答案:

答案 0 :(得分:1)

您可以将套接字状态上移到父组件,或者将事件初始化移动到在整个应用程序中共享一次的自定义钩子,也可以移到此处的useEffect钩子,以便仅在初始渲染时运行

最简单的选择也许是后一种选择,您可以像这样包装只想一次编写的代码行:

useEffect(() => {
  ioClient.emit('join', {roomid: roomId});
    ioClient.emit('connected', {roomid: roomId} );
    ioClient.on('message', (msg) => {
      const messageObject = {
        username: msg.from,
        message : msg.body,
        timestamp: msg.timestamp
      };
      addMessage(messageObject);
    });
}, []);

最后一个空数组表示它将仅在初始渲染时运行,而不会再次运行,因为它没有依赖性。


更新

您可能会或可能不会遇到关闭或计时问题,但是为了安全起见,将“ addMessage(messageObject);`”行替换为:

setMessages((previousMessages) => [messageObject, ...previousMessages]);

这与addMessage函数具有相同的作用,但是通过将回调函数传递给setMessages,可以避免从外部使用状态对象。