[英]SocketIO - Backend emit() event doesn't reach React client
I have been trying for a long time to implement a chat in React and Express using SocketIO and I am very close to finish, but unfortunately I've hit a dead end because a function that should work doesn't.很长一段时间以来,我一直在尝试使用 SocketIO 在 React 和 Express 中实现聊天,并且我非常接近完成,但不幸的是,我遇到了死胡同,因为应该工作的 function 不起作用。
I can't seem to be able to link emit()
from inside a join()
to a socket.on
on the client (React).我似乎无法将
emit()
从join()
内部链接到客户端(React)上的socket.on
。
I have been following some guides, but their code just works when mine does not.我一直在关注一些指南,但他们的代码在我的不工作时才有效。
Why can't I get anything in the client when emit()
is inside a join()
?当
emit()
在join()
中时,为什么我无法在客户端获取任何内容?
'use strict';
import express from 'express';
import { Server } from 'socket.io';
import { createServer } from 'http';
import cors from 'cors';
import bodyParser from 'body-parser';
import config from './config.js';
import authRoutes from './routes/authRoutes.js';
import userRoutes from './routes/userRoutes.js';
import roomRoutes from './routes/roomRoutes.js';
import chatRoutes from './routes/chatRoutes.js';
const app = express();
const server = createServer(app);
const io = new Server(server, {
cors: {
origin: ['http://localhost:3000', 'http://localhost:3001'],
},
});
app.use(express.json());
app.use(cors());
app.use(bodyParser.json());
app.use('/api/auth', authRoutes);
app.use('/api/users', userRoutes);
app.use('/api/rooms', roomRoutes);
app.use('/api/chat', chatRoutes);
const users = [];
const userJoin = (id, room, socketId, name) => {
const user = { id, room, socketId, name };
!users.some(
(user) => user.id === id && user.room === room && user.name === name
) && users.push(user);
return user;
};
const getCurrentUser = (socketId) => {
return users.find((user) => user.socketId === socketId);
};
const userLeave = (socketId) => {
const index = users.findIndex((user) => user.socketId === socketId);
if (index !== -1) {
return users.splice(index, 1)[0];
}
};
const getRoomUsers = (room) => {
return users.filter((user) => user.room === room);
};
const messageFormat = (messageText, sentBy) => {
const message = { messageText, sentBy, timestamp: new Date().toUTCString() };
return message;
};
const botName = 'BOT';
io.on('connection', (socket) => {
// Connecting
console.log('A user has connected.');
// Join room
socket.on('joinRoom', ({ id, chatID, name }) => {
const user = userJoin(id, chatID, socket.id, name);
socket.join(user.room, () => {
// socket.emit('getMessage', messageFormat('Welcome to Landmarks', botName));
// socket.broadcast
// .to(user.room)
// .emit('sendMessage', messageFormat(`${user.name} has joined the chat.`, botName));
// Send user and room info
io.to(user.room).emit('getUserRooms', {
room: user.room,
users: getRoomUsers(user.room),
});
// socket.on('sendUserRooms', () => {
// const user = getCurrentUser(socket.id);
// console.log(user);
// });
});
});
// Send message
socket.on('sendMessage', ({ sentBy, messageText }) => {
const user = getCurrentUser(socket.id);
io.to(user.room).emit('getMessage', messageFormat(messageText, user.id));
});
// Disconnecting
socket.on('disconnect', () => {
const user = userLeave(socket.id);
if (user) {
io.to(user.room).emit(
'sendMessage',
messageFormat(`${user.name} left the chat.`, user.id)
);
io.to(user.room).emit('getUserRooms', {
room: user.room,
users: getRoomUsers(user.room),
});
}
console.log('User has disconnected');
});
});
server.listen(config.port, () => {
console.log(`App is listening on url http://localhost:${config.port}`);
});
This is how my app is structured:这是我的应用程序的结构:
function App() {
return (
<BrowserRouter>
<Routes>
<Route
path='/'
element={
<PrivateRoute>
<Home />
</PrivateRoute>
}
>
<Route index element={<LandingPage />} />
<Route path='rooms' element={<LandingPage />}>
<Route path='new' element={<CreateRoom />} />
<Route path=':roomID' element={<RoomItem />} />
<Route path=':roomID/edit' element={<EditRoom />} />
<Route path='join/:inviteToken/' element={<JoinRoom />} />
</Route>
<Route path='profile/:id' element={<Profile />} />
</Route>
<Route path='login' element={<Login />} />
<Route path='register' element={<Register />} />
<Route path='set-avatar' element={<SetAvatar />} />
<Route path='*' element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
Inside Room Item is Drawer and inside Drawer are both Chat and Members.房间内项目是抽屉,抽屉内既是聊天又是成员。
// inside Room Item this is the only socketIO call
useEffect(() => {
if (currentRoom) {
dispatch(getMessages(currentRoom.chatID));
dispatch(roomActions.setCurrentChat(currentRoom.chatID));
dispatch(chatActions.reset());
}
}, [currentRoom, dispatch, currentUserID]);
useEffect(() => {
if (currentChat) {
socket.emit('joinRoom', {
id: currentUserID,
chatID: currentChat,
name: name,
});
}
console.log('do i get here');
}, [currentChat, currentUserID, name]);
I am importing socket using import socket from '../SocketIO/socket';
我正在使用
import socket from '../SocketIO/socket';
with和
import io from 'socket.io-client';
const socket = io('ws://localhost:8080');
export default socket;
And here is the Members component.这是成员组件。 Here I am only trying to get which users are in which rooms:
在这里,我只是想知道哪些用户在哪些房间:
import { List } from 'antd';
import { useEffect } from 'react';
import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import socket from '../../SocketIO/socket';
import { roomActions } from '../roomSlice';
import classes from './Members.module.css';
export default function Members({ members, ownerID, currentUserID, chatID }) {
const { onlineUsers } = useSelector((state) => state.room);
const [online, setOnline] = useState([]);
const [offline, setOffline] = useState([]);
const dispatch = useDispatch();
socket.on('getUserRooms', ({ room: roomID, users }) => {
dispatch(roomActions.setOnlineUsers({ room: roomID, users }));
console.log('here');
});
useEffect(() => {
console.log(onlineUsers);
setOnline(
members.filter((el) => {
return onlineUsers.some((foo) => foo.id === el.id);
})
);
setOffline(
members.filter((el) => {
return onlineUsers.every((foo) => foo.id !== el.id);
})
);
}, [onlineUsers, members, chatID]);
// console.log('online', online);
// console.log('offline', offline);
return (<></>);
I have tried moving socket.on('getUserRooms')
everywhere, but it just doesn't gets fired up.我试过到处移动
socket.on('getUserRooms')
,但它并没有被启动。
You need to make your socket available everywhere I guess.我猜你需要让你的套接字在任何地方都可用。 You can achieve this by creating a separate file and defining a react context using createContext.
您可以通过创建一个单独的文件并使用 createContext 定义一个反应上下文来实现这一点。
//websocket.js import React, {createContext } from 'react' import openSocket from "socket.io-client"; const ENDPOINT = "http://localhost:3000/" const WebSocketContext = createContext(null) export { WebSocketContext } export default ({ children }) => { let socket; let ws; if (,socket) { socket = openSocket(ENDPOINT: {transports.["websocket"]}) socket,on("eventname". data=>{ console:log(data) }) ws = { socket, socket. } } return ( <WebSocketContext.Provider value={ws}> {children} </WebSocketContext.Provider> ) }
Then, you wrap the context around your routes so you can use socket inside the components.然后,将上下文包装在路由周围,以便可以在组件内使用套接字。
import WebSocketProvider from "path/to/websocket.js" function App(){ <WebSocketProvider> <BrowserRouter> //... </BrowserRouter> </WebSocketProvider> }
you can then use the socket inside any of the components by importing the WebSocketContext然后,您可以通过导入 WebSocketContext 在任何组件中使用套接字
import {WebSocketContext} from "path/to/websocket.js" import {useContext} from "react" function AnyOtherComponents(){ let {socket} = useContext(WebSocketContext) useEffect(()=>{ socket.on("event", data=>{ //... }) }) return <></> }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.