I'm working on a React project using WebSockets to receive real-time updates. However, I'm encountering an issue where my component's state resets to the default value every time a WebSocket message is received. I've been trying to debug this, but haven't figured out why this is happening. Thank you for your help in advance :).
Reducer
const initialState = {
name: "",
message: "",
word: "",
color: "#000000",
eraseMode: false,
strokeWidth: 2,
eraserWidth: 10,
isDrawing: false,
id: null,
turnID: null,
names: null,
scores: null,
msgArr: [],
}
function reducer(state, action) {
switch (action.type) {
case "setAll":
return {
...state,
id: action.payload.id,
turnID: action.payload.turnID,
names: action.payload.names,
scores: action.payload.scores,
}
case "setName":
return { ...state, name: action.payload }
case "setMessage":
return { ...state, message: action.payload }
case "setWord":
return { ...state, word: action.payload }
case "setColor":
return { ...state, color: action.payload }
case "setErasemode":
return { ...state, eraseMode: action.payload }
case "setStrokeWidth":
return { ...state, strokeWidth: action.payload }
case "setEraserWidth":
return { ...state, eraserWidth: action.payload }
case "setIsDrawing":
return { ...state, isDrawing: action.payload }
case "setId":
return { ...state, id: action.payload }
case "setTurnID":
return { ...state, turnID: action.payload }
case "setNames":
return { ...state, names: action.payload }
case "setScores":
return { ...state, scores: action.payload }
case "addMsg":
return { ...state, msgArr: [...state.msgArr, action.payload] }
default:
throw new Error()
}
}
functional component
const [state, dispatch] = useReducer(reducer, initialState)
const ws = useRef(null)
const url = "ws://localhost:9833"
const p = useParams()
useEffect(() => {
// Initialize WebSocket
const connectWebSocket = () => {
if (ws.current) {
ws.current.onerror = ws.current.onopen = ws.current.onclose = null
ws.current.close()
}
ws.current = new WebSocket(`${url}/${p.roomID}`)
console.log("Attempting to connect to WebSocket:", `${url}/${p.roomID}`)
ws.current.onopen = () => {
console.log("WebSocket connection opened")
}
ws.current.onerror = (error) => {
console.error("WebSocket error:", error)
}
ws.current.onclose = () => {
console.log("WebSocket connection closed")
// Attempt to reconnect in case of a connection failure
toast.error("Connection lost!")
ws.current = null
dispatch({ type: "setId", payload: null })
setTimeout(() => connectWebSocket(), 1000)
}
ws.current.onmessage = (message) => {
console.log("when WebSocket message received:", state)
//here state is always equal to initial state
const msg = JSON.parse(message.data)
switch (msg.type) {
case 0:
if (msg.turnID === msg.id) {
dispatch({ type: "setWord", payload: msg.word })
}
dispatch({
type: "setAll",
payload: {
id: msg.id,
turnID: msg.turnID,
names: msg.names,
scores: msg.scores,
},
})
break
case 1:
break
case 3:
if (msg.isTrue) {
dispatch({
type: "addMsg",
payload: `G ${state.names[msg.id]} guessed the word!đź‘Źđź‘Ź`,
})
dispatch({ type: "setScores", payload: msg.scores })
} else {
dispatch({
type: "addMsg",
payload: `B ${state.names[msg.id]}: ${msg.message}`,
})
}
break
case 4:
dispatch({
type: "addMsg",
payload: `S ${state.names[msg.turnID]} is drawing now.`,
})
dispatch({ type: "setTurnID", payload: msg.turnID })
if (msg.turnID === state.id)
dispatch({ type: "setWord", payload: msg.word })
break
case 6:
dispatch({
type: "addMsg",
payload: `O ${msg.name} joined the room.`,
})
dispatch({ type: "setScores", payload: msg.scores })
dispatch({ type: "setNames", payload: msg.names })
break
case 7:
dispatch({
type: "addMsg",
payload: `R ${state.names[msg.id]} left the room.`,
})
dispatch({ type: "setScores", payload: msg.scores })
dispatch({ type: "setNames", payload: msg.names })
break
default:
break
}
}
}
connectWebSocket()
// Cleanup on component unmount
return () => {
if (ws.current) {
ws.current.onerror = ws.current.onopen = ws.current.onclose = null
ws.current.close()
}
}
}, [p.roomID])
Initially, I was using the useState hook after that I used useReducers in both cases it happened. I have checked that after dispatch my state updates but when a message is received it again comes to the Initial state.