admin管理员组

文章数量:1201410

Body: I’m building a real-time chat application using the MERN stack, where the frontend uses React, the backend uses Node.js with WebSocket, and MongoDB stores chat history.

Problem: When I send a chat message from one browser tab, it successfully broadcasts to the WebSocket server and renders in that tab. However, in other tabs where the chat is open, the new message is not rendered until I refresh or rejoin the chat.

Here’s what I’ve tried:

Ensuring that the WebSocket connection broadcasts messages to all clients. Using React’s useEffect to listen for onmessage events and update the state (setMessages). Using a useRef to hold the latest messages and avoid stale closures. Ensuring WebSocket connections are established and open in all tabs.

  const { ws, isReady } = useWebSocket();
  const navigate = useNavigate();
  const { session } = useContext(createSessionContext);
  const [chat, setChat] = useState<string>(""); 
  const [messages, setMessages] = useState<ChatMessage[]>([]); 
  const location = useLocation();
  const messageRef = useRef<ChatMessage[]>([]); 

  useEffect(() => {
    if (Array.isArray(location.state) && location.state.length > 0) {
      setMessages(location.state);
      messageRef.current = location.state; 
    }
  }, [location.state]);

  useEffect(() => {
    if (!session) {
      navigate("/");
      return;
    }

    if (isReady && ws?.readyState === WebSocket.OPEN) {
      ws.onmessage = (event: MessageEvent) => {
        const data = JSON.parse(event.data);

        const newMessage: ChatMessage = {
          name: data.payload.name,
          message: data.payload.message,
          upvotes: [],
          chatId: data.payload.chatId,
        };

        messageRef.current = [...messageRef.current, newMessage];
        setMessages([...messageRef.current]);
      };

      ws.onerror = (e) => {
        console.error("WebSocket error:", e);
      };
    }

    return () => {
      if (ws) {
        ws.onmessage = null;
        ws.onerror = null;
      }
    };
  }, [ws, isReady, session, navigate]);

  const SendChat = () => {
    if (isReady && ws && ws.readyState === WebSocket.OPEN && chat.trim() !== "") {
      ws.send(
        JSON.stringify({
          type: "SEND_MESSAGE",
          payload: {
            sessionId: session,
            message: chat,
          },
        })
      );
      setChat("");
    }
  };

  return (
    <div className="bg-slate-400 max-w-screen h-screen">
      <div className="max-w-screen-md mx-auto p-10 relative top-20 flex flex-col bg-slate-600 text-white rounded-md">
        <h1 className="text-center">Chat</h1>
        <div className="flex border border-white justify-between p-2 rounded-md mt-2">
          <div className="border-collapse">
            <h2 className="ml-1.5">All Chats</h2>
            <div className="border-collapse pt-5 pb-5">
              {messages.length > 0 ? (
                <div>
                  {messages.map((message, index) => (
                    <div
                      className="flex font-semibold bg-slate-900 pt-1 pb-1 mb-2.5 justify-between rounded-md"
                      key={message.chatId}
                    >
                      <div className="flex gap-2">
                        <div className="text-slate-200">{message.name}:</div>
                        <div className="text-slate-200">{message.message}</div>
                      </div>
                      <div className="flex items-center gap-2.5">
                        <div className="text-white font-bold cursor-pointer border rounded-full p-1">
                          <FaArrowUpLong />
                        </div>
                        <div>{message.upvotes.length}</div>
                      </div>
                    </div>
                  ))}
                </div>
              ) : (
                <div className="text-slate-200">No messages yet</div>
              )}
            </div>
            <input
              className="bg-slate-800 p-1.5 mr-1.5 rounded-md outline-none"
              type="text"
              placeholder="chat"
              value={chat}
              onChange={(e: ChangeEvent<HTMLInputElement>) => setChat(e.target.value)}
            />
            <button onClick={SendChat} className="bg-slate-800 rounded-md p-1.5">
              Send
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};        ````````

本文标签: reactjsReact WebSocket Chat Messages Not Rendering in Other Tabs Until RejoinedStack Overflow