I've created a application for my company to manage diffrent things. I first started realizing it with Class-Components, now switched to Functional components.
The issue that i'm facing is, that in one function inside Websocket onMessage uses old/empty state.
This is how the application currently is built.
const DocumentControl = ({ createWebsocket, logOut }) => {
const [elementList, setElementList] = useState([]);
const webSocket = useRef(null);
useEffect(() => {
webSocket.current = createWebsocket();
webSocket.current.onmessage = (messageEvent) => {
console.log(elementList);
if (devComm) {
console.log(JSON.parse(messageEvent.data));
}
processMessage(JSON.parse(messageEvent.data));
};
window.addEventListener("beforeunload", () => {
logOut(true);
});
}, []);
useEffect(() => {
loadElements();
}, [menu]);
const processMessage = (message) => {
var newArr, index;
switch (message.type) {
case "document":
var elementItem = message.data;
newArr = [...elementList]; // here elementList is always []
...
break;
default:
if (devComm) {
console.log("---Unknown WSMessage!---");
}
}
};
}
There is obviously more logic but this may be sufficient to describe my problem. Basically i'm loading from the Server my ElementList if the Menu changes. Whenever an Element on the Server-Side is updated, I send a message through Websockets to all clients, so all are up-to-date.
---My Issue---
Loading the Elements from Server and using setElementList works fine. But whenever I receive a message through websockets, the state elementList is always empty.
I made a button which displays the current elementList and there the List is correctly.
For example: I have 4 Elements in my list. Because of Message in Websockets i want to add to my current list the new Element. But the elementList is [] inside processMessage, so I add the new element to an [] and after setElementList all other elements are gone (because of empty array previously)
My first thought was, that (because I get the Websocket element from parent) maybe it uses diffrent instance of elementList, which is initialized as empty [].
But it would not make sense, because setElementList still affects the "original" elementList.
I also tried using elementList with useRef(elementList) and accessing it with ref.current but still didn't change the outcome.
here is how the createWebsocket is implemented:
const createWebsocket = () => {
if (!webSocket.current) {
var uri = baseURI.replace("http://", "ws://");
console.log("Create new Websocket");
console.log("Websocket: " + uri + "websocket/");
let socket = new WebSocket(uri + "websocket/" + user.Token);
socket.onopen = () => {};
socket.onclose = (closeEvent) => {
console.log("closed socket:");
if (closeEvent.code !== 3001) {
logOut(false);
if (closeEvent !== null && closeEvent.reason.length > 0) {
alert(closeEvent.reason);
}
}
};
socket.onerror = () => {
logOut(true, false);
alert("Something went wrong");
};
webSocket.current = socket;
}
return webSocket.current;
};
Any Ideas why elementList is diffrent inside ProcessMessage then in other functions of the Component?
--------- UPDATE -------
I could temporary fix it, by using this workaround:
const elementsRef = useRef([]);
useEffect(() => {
elementsRef.current = elementList;
}, [elementList]);
and then accessing elementsRef.current But there must be an more elegant soltuion to this