Home > OS >  React state variable returns to its initial value when socket io event is triggered from the server
React state variable returns to its initial value when socket io event is triggered from the server

Time:12-21

I have the following code of which is a part of a simple React Flask socketio chat application:

const ip=window.location.hostname
const socket = io("http://" ip ":5000");
export default function Homepage() 
{

  const currUser=useSelector(state=>state.authReducer).loggedInUser
  const [chats, setChats] = useState([])
  const [selectedChatID, setSelectedChatID] = useState("")
  const [selectedChatIndex, setSelectedChatIndex] = useState(-1)

  const getChatsDataFromDB = async() => 
  {
    let chats = await messagesSVR.getMessages()
    setChats(chats.data.data)
  }

  const handleReceiveMessage=(message)=>
  {
    
    let newMessageChatIndex = [...chats].findIndex(chat =>
       {
        
        return chat["chat_id"] == message["chatID"]})

    
    const updatedChats = Object.assign([], chats, {
    [newMessageChatIndex]: {
        chat_id: selectedChatID,
        chat_messages: [...chats[newMessageChatIndex].chat_messages,
        message],
        },
    })
    
    setChats(updatedChats)

    
  }

  useEffect(()=>
  {
    socket.on("receive-message",(message)=>
    {
      handleReceiveMessage(message)
    })

    socket.emit("add-user",{user_email:currUser["_id"]}); 

    return ()=>
    {
      socket.off('receive-message');
    }
  },[])
  
  useEffect(() => {

    getChatsDataFromDB()


  }, [])



  useEffect(() => {
    let currChatIndex = chats.findIndex(chat => chat["chat_id"] == selectedChatID)
    setSelectedChatIndex(currChatIndex)

  }, [selectedChatID, chats])

  const handleSendNewMessage = async (messageText) => {
    let message_id=v4()
    let newMessage=
    {
      _id:message_id,
      to:chats[selectedChatIndex]["partner_id"],
      chatID:selectedChatID,
      userID:currUser["_id"],
      text:messageText,
      sentAt:new Date()
    }
    
    try {

      //Adding message to server
      let resp = await messagesSVR.addMessage(newMessage)

      //Executed if message added properly
      if (resp.status == 200) {

        const updatedChats = Object.assign([], chats, {
          [selectedChatIndex]: {
              chat_id: selectedChatID,
              partner_id:[...chats][selectedChatIndex].partner_id,
              chat_messages: [...chats[selectedChatIndex].chat_messages,
              newMessage],
          },
      })
        setChats(updatedChats)
        socket.emit("send-message",newMessage)
        
      }
    } catch (err) {
        console.log(err)
    }

  }

When I run the app with two tabs opened in the browser, and send a message from one tab ( tab number 1 for the sake of argument) to tab number 2 using the send-message event,the message is indeed received in tab number 2 through the receive-message event in handleReceiveMessage function, but for some reason the chats state variable value is an empty array ( I can see it when I print console.log(chats)) , though it was previously loaded with chats data from data base.

Is there any way to fix this?

CodePudding user response:

useEffect seems to be refering to the initial values through handleReceiveMessage

const handleReceiveMessage = (message) =>
  {
    
    let newMessageChatIndex = [...chats].findIndex(chat =>
       {
        
        return chat["chat_id"] == message["chatID"]})

    
    const updatedChats = Object.assign([], chats, {
    [newMessageChatIndex]: {
        chat_id: selectedChatID,
        chat_messages: [...chats[newMessageChatIndex].chat_messages,
        message],
        },
    })
    
    setChats(updatedChats)

    
  }

const handleReceiveMessageRef = useRef();
//refer to latest version
handleReceiveMessageRef.current = handleReceiveMessage

const currUserRef = useRef();
currUserRef.current = currUser;

  useEffect(()=>
  {
    socket.on("receive-message",(message)=>
    {
      handleReceiveMessageRef.current(message)
    })

    socket.emit("add-user",{user_email:currUserRef.current["_id"]}); 

    return ()=>
    {
      socket.off('receive-message');
    }

  },[])

The problem you are facing is related to referring the latest props in useEffect and why it happens, it will give you an idea on how to handle such problems

Hope it helps

  • Related