I have a React app that connects to a WebSocket using react-use-websocket
. Messages are received asynchronously, processed by receiveHandler
and then the socketMessages
state is updated with the response. Sample code:
import useWebSocket from 'react-use-websocket';
const [socketMessages, setSocketMessages] = useState([])
const { lastJsonMessage } = useWebSocket(path);
useEffect(() => {
const processedResponse = receiveHandler(lastMessage)
setSocketMessages([...socketMessages, processedResponse])
}, [lastMessage]);
const receiveHandler = (lastMessage) =< {
// do receive processing on lastMessage
return processedLastMessage
}
My issue is that messages are sometimes arriving in quick succession and new state updates are happening before existing updates are finished, causing messages to get lost.
Is there a simple way to handle this within the native functionality? Or, do i need a module to implement some form of queue?
I think you can achieve that using UseRef()
and setTimeOut()
with function to check if your value is updated.
This should do the purpose:
import React, {useState, useEffect, useRef} from 'react';
import useWebSocket from 'react-use-websocket';
//
const WebSocketComponent = ({path}) =>{
//
const [socketMessage, setSocketMessage] = useState([]);
const {lastJsonMessage} = useWebSocket(path);
const messageQueue = useRef([])
const processingQueue = useRef(false)
//
const recieveHandler = (message) =>{
// process the received message
// implement your message processing logic here ..
return processedMessage;
}
const processQueue = () => {
if(processingQueue.current || messageQueue.current.Length ===0){
return;
}
processQueue.current = true;
const processNextMessage = () => {
if(messageQueue.current.Length === 0){
processingQueue.current = false;
return;
}
//
const nextMessage = messageQueue.current.shift();
const processedMessage = receiveHandler(nextMessage);
//
setSocketMessage((prevMessage)=>[...prevMessages, processedMessage]);
// schedule the next message to be processed after the state update:
setTimeout(processNextMessage, 0);
};
processNextMessage();
};
useEffect(()=>{
if(lastJsonMessage){
messageQueue.current.push(lastJsonMessage);
processQueue();
}
},[lastJsonMessage])
}
I didn't run the code in vsc so please let me know if it worked.