useState hook's set State function not working properly with socket.io

Viewed 1122

I have a component that uses react hooks and socketio:

import React, { useState, useEffect } from "react";
import io from "socket.io-client";

const Live = () => {
  const [messages, setMessages] = useState([]);
  const ENDPOINT = "localhost:5000";

  useEffect(() => {
    socket = io(ENDPOINT);
    socket.on("message", (message) => {
      setMessages((messages) => [message, ...messages]);
      //setMessages([message, ...messages]); //It doesn't work
    });
  }, [ENDPOINT]);

  // rest of the code

};

If I use the setMessages([message, ...messages]), it doesn't work and upon receiving a new message from socket, all the previous message in messages array are gone. What is the reason behind this behavior?

1 Answers

I don't recommend useState here to do what you're doing. Instead, consider useReducer

const Live = () => {
  const ENDPOINT = "localhost:5000";

  const [{ messages }, dispatch] = useReducer((state, action) => {
    if (action.type === 'NEW_MESSAGE') {
      state.messages.push(action.message)
      return state
    }
    return state
  }, { messages: [] })

  useEffect(() => {
    socket = io(ENDPOINT);
    socket.on("message", (message) => {
      dispatch({ type: 'NEW_MESSAGE', message })
    });
  }, [ENDPOINT])

  // rest of the code
};

from the React docs on useReducer

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

In your case, the next messages state depends on the previous messages state.

Related