最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

React + Express:对于某些用户来说,服务器中的数据似乎没有传递到前端

网站源码admin33浏览0评论

React + Express:对于某些用户来说,服务器中的数据似乎没有传递到前端

React + Express:对于某些用户来说,服务器中的数据似乎没有传递到前端

我做了一个网页游戏,用户可以创建房间并让其他用户加入。每当用户加入房间时,应该向加入用户本人发送一条欢迎消息,并向房间中的其他用户发送“xxx 已加入”消息。房间页面左侧的个人资料图片应更新以显示房间中每个用户的个人资料图片。

我用两个账号测试了,user1创建房间时,一切正常。但是,当 user2 加入房间时,user1 页面中的所有内容都已正确更新,但 user2 页面中没有任何内容更新(没有欢迎消息、没有个人资料图片等),并且

console.log("roomData", roomData)
甚至没有在 user2 的页面中记录任何内容。

这是我的后端代码index.js:

// utils
const process = require("process");
const cors = require("cors");
const socket = require("socket.io");

// imports
const verifyToken = require("./middleware/VerifyToken");
const { setUsername, join, addRoom, getRoom, deleteRoom, getCurrentUser, getUsersInRoom, leave } = require("./middleware/roomManagement");
const { newGame, updateGame, removeGame } = require("./middleware/gameManagement");

require("dotenv").config();

// express app
const express = require("express");
const app = express();
const portNumber = process.env.PORT_NUMBER || 8080;

// middleware
app.use(express());
app.use(express.urlencoded({ extended: false }));
app.use(cors());

app.use(verifyToken);

var server = app.listen(portNumber, (e) => {
    if(e) {
        console.log("Failed to start the server with error message: " + e);
    }else {
        console.log(`Web server started and running at http://localhost:${portNumber}`);
    }
});

const io = socket(server);

io.on("connection", (socket) => {
    console.log("socket connected");
    socket.on("changeName", (username) => {
        setUsername(socket.id, username);
    });

    socket.on("joinRoom", ({userId, roomId, username, isHost}) => {
        let roomData = getRoom(roomId);

        console.log("outterRoomData", roomData);
        if(roomData && roomData.inGame) {
            console.log("in if");
            socket.emit("roomData", roomData);
            return;
        }else {
            console.log("in else");
            // create user
            const curUser = join(socket.id, userId, roomId, username, isHost);
            socket.join(curUser.roomId);

            // welcome message
            socket.emit("message", {
                username: curUser.username,
                text: `Welcome, ${curUser.username}!`,
                isCipher: false
            });

            // show that the user joined
            socket.broadcast.to(curUser.roomId).emit("message", {
                username: curUser.username,
                text: `${curUser.username} has joined the room`,
                isCipher: false
            });

            const users = getUsersInRoom(curUser.roomId);

            if(roomData) {
                // update roomData for room if it alreade exist
                roomData.users = users;
            }else {
                // create room if room is not already exist
                const hostId = curUser.userId;
                const status = false;
                roomData = addRoom(roomId, users, hostId, status);
            }

            console.log("innerRoomData", roomData);
            // send roomData to client side
            io.to(curUser.roomId).emit("roomData", roomData);
        }
    });

    // start game
    socket.on("startGame", (roomId, lastLose) => {
        let room = getRoom(roomId);
        if(room) {
            // set roomData.inGame to true and send it to client side
            room.inGame = true;
            io.to(roomId).emit("roomData", room);

            const game = newGame(roomId, lastLose);
            io.to(roomId).emit("game", game);
        }
    });

    // update game status
    socket.on("game", (game) => {
        const curUser = getCurrentUser(socket.id);
        const updatedGame = updateGame(curUser.roomId, game);
        io.to(curUser.roomId).emit("game", updatedGame);
    });

    socket.on("endGame", (roomId) => {
        let room = getRoom(roomId);
        if(room) {
            // set roomData.inGame to false and sned it to client side
            room.inGame = false;
            io.to(roomId).emit("roomData", room);

            // delete game in data
            removeGame(roomId);
        }
    });

    // user sending message
    socket.on("chat", (text) => {
        const curUser = getCurrentUser(socket.id);

        io.to(curUser.roomId).emit("message", {
            username: curUser.username,
            text: text,
            isCipher: true
        });
    });

    socket.on("called", (name) => {
        const curUser = getCurrentUser(socket.id);
        io.to(curUser.roomId).emit("called", name);
    });

    // user leave the room
    socket.on("leave", () => {
        const curUser = leave(socket.id);
        if(curUser) {
            socket.leave(curUser.roomId);
            // message shows user leaving
            io.to(curUser.roomId).emit("message", {
                username: curUser.username,
                text: `${curUser.username} has left the room`
            });

            const users = getUsersInRoom(curUser.roomId);
            if(users.length == 0) {
                // delete room if there is no user in it
                deleteRoom(curUser.roomId);
            }else if(users.length > 0) {
                const room = getRoom(curUser.roomId);

                // set new host if host left
                if(room.hostId === curUser.userId) {
                    room.hostId = users[0].userId;
                    users[0].isHost = true;
                }

                // update users in room
                room.users = users;

                io.to(curUser.roomId).emit("roomData", room);
            }
        }
    });
});

我在前端有 Room.js,如下所示:

import { useState, useEffect } from "react";
import { useDispatch } from "react-redux";
import { useParams, useNavigate } from "react-router-dom";
import { ref, getDownloadURL } from "firebase/storage";
import { ClipboardCopyIcon } from "@heroicons/react/outline";

import { process } from "../../services/store/action";
import { to_Decrypt, to_Encrypt } from "../../utils/aes";
import { useAuth } from "../../contexts/AuthContext";
import { useAutoScroll } from "../../utils/autoScroll";
import { storage } from "../../config/firebase";
import { GameArea } from "./GameArea";

export default function Room({ socket }) {
    const navigate = useNavigate();

    const [text, setText] = useState("");
    const [messages, setMessages] = useState([]);
    const [users, setUsers] = useState([]);
    const [userpics, setUserpics] = useState({});
    const [hostId, setHostId] = useState("");
    const [inGame, setInGame] = useState();

    const { roomId } = useParams();
    const { setError } = useAuth();
    const dispatch = useDispatch();
    const userRef = useAutoScroll(userpics);
    const chatRef = useAutoScroll(messages);

    // useEffect(() => {
    //     // handle messages
    //     const dispatchProcess = (encrypt, msg, cipher) => {
    //         dispatch(process(encrypt, msg, cipher));
    //     };

    //     socket.on("message", (msgdata) => {
    //         // decypt the message
    //         const ans = to_Decrypt(msgdata.text, msgdata.isCipher);
    //         dispatchProcess(false, ans, msgdata.text);

    //         setMessages((prevMessages) => [
    //             ...prevMessages,
    //             {username: msgdata.username, text: ans}
    //         ]);
    //     });

    //     // display users
    //     socket.on("roomData", async (roomData) => {
    //         console.log("roomData", roomData);
    //         setHostId(roomData.hostId);
    //         setInGame(roomData.inGame);

    //         let tempPics = new Map();
    //         let tempUsers = [];
    //         await Promise.all(
    //             roomData.users.map(async (user) => {
    //                 const picRef = ref(storage, 'profilePic/' + user.userId + '.jpg');
    //                 try{
    //                     const url = await getDownloadURL(picRef);
    //                     tempPics.set(user.userId, url);
    //                     tempUsers.push(user);
    //                 }catch (e) {
    //                     console.log(e.message);
    //                 }
    //             })
    //         );
    //         setUserpics(tempPics);
    //         setUsers(tempUsers);
    //     });

    //     return () => {
    //         socket.off("message");
    //         socket.off("roomData");
    //     }
    // }, [dispatch, messages, socket]);

    useEffect(() => {
        const dispatchProcess = (encrypt, msg, cipher) => {
          dispatch(process(encrypt, msg, cipher));
        };
      
        const handleMessage = (msgdata) => {
          const ans = to_Decrypt(msgdata.text, msgdata.isCipher);
          dispatchProcess(false, ans, msgdata.text);
      
          setMessages((prevMessages) => [
            ...prevMessages,
            { username: msgdata.username, text: ans },
          ]);
        };
      
        const handleRoomData = async (roomData) => {
          console.log("roomData", roomData);
          setHostId(roomData.hostId);
          setInGame(roomData.inGame);
      
          let tempPics = new Map();
          let tempUsers = [];
          await Promise.all(
            roomData.users.map(async (user) => {
              const picRef = ref(storage, 'profilePic/' + user.userId + '.jpg');
              try {
                const url = await getDownloadURL(picRef);
                tempPics.set(user.userId, url);
                tempUsers.push(user);
              } catch (e) {
                console.log(e.message);
              }
            })
          );
          setUserpics(tempPics);
          setUsers(tempUsers);
        };
      
        socket.on("message", handleMessage);
        socket.on("roomData", handleRoomData);
      
        return () => {
          socket.off("message", handleMessage);
          socket.off("roomData", handleRoomData);
        };
      }, [dispatch, socket]);      

    const sendData = () => {
        if(text !== "") {
            // encrypt the message
            const ans = to_Encrypt(text);
            socket.emit("chat", ans);
            setText("");
        }
    };

    const copyRoomId = () => {
        navigator.clipboard.writeText(roomId);
    }

    const leaveRoom = () => {
        socket.on("roomData", (roomData) => {
            setInGame(roomData.inGame);
        }); 

        if(inGame) {
            setError("Game in process, please do not leave.");
        }else {
            socket.emit("leave");
            navigate("/");
        }
    }

    const userIds = users.map(user => user.userId);

    return(
        <div>
            <div id="roomIdDisplay">Room ID: {roomId}
                <button onClick={copyRoomId}><ClipboardCopyIcon id="copyIcon" /></button>
            </div>

            <button className="logoutbutton" onClick={leaveRoom}>Leave</button>

            <div id="roomUsers" ref={userRef}>
                <div id="usersContent">
                    {userIds.map((userId, index) => {
                        const url = userpics.get(userId);
                        return (
                            <div key={index}>
                                <img src={url} alt="profilepic" className="roomProfilepic" />
                            </div>
                        );
                    })}
                </div>
            </div>

            <div>
                <GameArea socket={socket} roomId={roomId} users={users} host={hostId} />
            </div>

            <div id="chatBox">
                <div id="chatHistory" ref={chatRef}>
                    <div id="chatContent">
                        {messages.map((i, index) => {
                            return (
                                <div key={index} className="message">
                                    <p>{i.username}: {i.text}</p>
                                </div>
                            );
                        })}
                    </div>
                </div>
                <div id="sendInput">
                    <input
                        id="msgInput"
                        value={text}
                        onChange={(e) => setText(e.target.value)}
                        onKeyPress={(e) => {
                            if(e.key === "Enter") {
                                sendData();
                            }
                        }}
                    />
                    <button onClick={sendData}>Send</button>
                </div>
            </div>
        </div>
    );
}

我还确保套接字正确传递到前端 App.js 中的 Room.js,如下所示:

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import React from "react";
import io from "socket.io-client";

import './index.css';
import { AuthProvider } from "./contexts/AuthContext";
import Register from "./components/auth/Register";
import Login from "./components/auth/Login";
import User from "./components/account/User";
import Profile from "./components/account/Profile";
import Room from "./components/games/Room";
import JoinRoom from "./components/games/JoinRoom";
import Background from "./components/layouts/Background";
import ErrorMessage from "./components/layouts/ErrorMessage";
import WithPrivateRoute from "./utils/WithPrivateRoute";

const socket = io.connect("/");

function App() {
  const generateRoomId = () => {
    let S4 = () => {
      return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }

    return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() +S4();
  }

  return (
    <AuthProvider>
      <Router>
        <Background />
        <ErrorMessage />
        <Routes>
          <Route exact path="/register" element={<Register />} />
          <Route exact path="/login" element={<Login />} />
          <Route exact path="/profile" element={
            <WithPrivateRoute>
              <Profile  socket={socket}/>
            </WithPrivateRoute>
          } />
          <Route exact path="/" element={
            <WithPrivateRoute>
              <User generateRoomId={generateRoomId} socket={socket}/>
            </WithPrivateRoute>
          } />
          <Route exact path="/join" element={
            <WithPrivateRoute>
              <JoinRoom socket={socket}/>
            </WithPrivateRoute>
          } />
          <Route path="room/:roomId" element={
            <WithPrivateRoute>
              <Room socket={socket} />
            </WithPrivateRoute>
          }/>
        </Routes>
      </Router>
    </AuthProvider>
  );
}

export default App;

有趣的事实是,当用户1离开房间时,用户2的页面就可以正确更新。

回答如下:
发布评论

评论列表(0)

  1. 暂无评论