Home > other >  How to correctly load data on WS event?
How to correctly load data on WS event?

Time:06-25

So. Server sends event to every client in specific room on message submit for other clients to load messages, so they can see that new message. React client correctly receives, but loads messages in weird way. It renders page with no messages and after few miliseconds loads correctly. It cause very ugly blink.

Client socket.io code:

useEffect(() => {
      loadRooms(userId).then(data => {
        dispatch(setRoomsList(data))
      })
      loadMessages(roomId).then(data => {
        dispatch(setMessageList(data))
      });

      socket.on('receive_message', data => {
        dispatch(addNewMessage({id: data.id, content: data.message, roomId: data.room, userName: data.userName}));
        console.log(messageList)
      })
    }, [dispatch, roomId, socket])

Client who sends message doesn't have this bug. On this client, axios request works correctly.

Submit message handler:

const handleMessageSubmit = e => {
      e.preventDefault()
      sendMessage(userName, currentMessage, roomId).then(data => {
        loadMessages(roomId).then(data => {
          dispatch(setMessageList(data))
          socket.emit('send_message', {message: currentMessage, room: roomId});
        })
        setCurrentMessage('')
      })
    }

Loading message normally with that handler work just fine, but with socket.io it is bugged.

How messages are displayed in page:

{messageList.map(message =>
                    <div sx={{overflow: 'auto'}} key={message.id} style={{display: 'block', width: '70vw', marginTop: '5px', clear: 'both'}}>
                      <div style={{wordWrap: 'break-word'}} key={message.id}>{message.userName}: {message.content}</div>
                    </div>
                  )}

messageList is redux state, which I get using mapStateToProps

Socket.io on the server side:

io.on('connection', (socket) => {
    let prevRoom = 1;
    console.log("Users's id", socket.id)
    
    socket.on('send_message', (data) => {
        socket.to(data.room).emit('receive_message', data.message)
        console.log("sent", data.message)
    })

    socket.on('join_room', (data) => {
        socket.leave(prevRoom)
        prevRoom = data;
        socket.join(data)
        console.log("joined")
    })
} )

CodePudding user response:

The idea behind sending data through web sockets is that you read it from message that you receive and then render. You don't do that here. You ignore the data in "receive_message" and call "loadMessages" that, I assume, loads full messages list from api. This extra call to api causes the ugly blink, but the code that resets messageList is not in question (probably in redux).

You need to get rid of extra api call and append the new message received via web socket to your existing message list

  • Related