我试图创建一种房间系统的消息传递系统,我正在与socket.io的一个React项目,它似乎没有连接正确。
这是相当复杂的,所以我会带您通过一个用例。
1.用户登录和它的问候与此页面:
如您所见,我的用户已在左下角登录
1.此用户现在要向某人发送消息让我们使用test,因为test是视图中的当前配置文件
1.用户单击配置文件视图右上角的消息按钮,这会将他们带到此屏幕:
他们现在可以向他们发送他们想要发送的任何消息
这就是现在的问题所在。很明显,测试会想看看管理员发送给他们什么,这就是我想要一个房间系统的地方。这样,当登录的用户点击用户发送消息时,它会创建一个房间,在那里两个用户可以互相发送消息。我曾试图通过www.example.com实现这socket.io因为我以前的GET和POST请求版本不是实时的。到目前为止你只能发送消息,用户之间没有任何种类的来回。
通过我的测试,我做了一个房间ID,并将其记录到控制台,如下所示:
joined room: admin admin_test test
{
sender: 'admin admin',
recipient: 'test test',
message: 'a',
time: '17:47',
room: 'admin admin_test test'
}
joined room: admin admin_test test
{
sender: 'test test',
recipient: 'admin admin',
message: 'a',
time: '17:47',
room: 'admin admin_test test'
}
这确实表明消息正在发送,并且它们在同一个房间ID下。我不确定他们为什么不接收消息。我希望有任何解决方案,以便这两个人可以在彼此之间来回发送消息。
下面是管理套接字的后端:
const { Server } = require("socket.io");
const socket = (server) => {
const io = new Server(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});
//On connection
io.on('connection', socket => {
//On join room
socket.on('join', room => {
socket.join(room);
console.log('joined room: ' + room);
});
//On message send
socket.on('send_message', (data) => {
//Log message
console.log(data);
//Emit to recipient
io.to(data.room).emit('receive_message', data);
});
});
};
module.exports = socket;
处理消息传递的客户端:
import { useEffect, useState, useRef } from 'react';
import io from 'socket.io-client';
import { ArrowLongUpIcon } from '@heroicons/react/24/outline';
export default function Message({sender, recipient, profilePicture, roomId}) {
const socket = io('http://localhost:8080');
const [message, setMessage] = useState('');
const [messages, setMessages] = useState([]);
const bottomRef = useRef(null);
//Sends message to server
const sendMessage = async () => {
//If input isnt empty
if (message !== '') {
//Formats message
const messageData = {
sender: sender,
recipient: recipient,
message: message,
time: new Date().getHours() + ':' + new Date().getMinutes(),
room: roomId
};
//Sends to back end
await socket.emit('send_message', messageData);
//Shows previously sent message
setMessages((list) => [...list, messageData]);
//Clears input
setMessage('');
};
};
useEffect(() => {
//Receive message from back-end
socket.on('receive_message', (data) => {
console.log(data);
console.log(roomId);
//If message is for this room
if (data.room === roomId) {
console.log(data);
//Show message
setMessages((list) => [...list, data]);
}
});
}, [roomId]);
useEffect(() => {
// Scroll to bottom every time messages change
bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
/* Messages */
<div class="flex flex-col h-full max-h-[750px] w-full px-4 py-6">
{/* Message list */}
<div class="h-full overflow-y-scroll pb-4">
<p class="text-center italic text-gray-400">Chat started with: <span class="font-semibold">{recipient}</span></p>
<div class="grid grid-cols-12">
{/* Individual message */}
{messages.map((messageContent, index) => {
return (
messageContent.sender === sender ? (
/* Sender */
<div key={index} class="col-start-6 col-end-13 p-2 rounded-lg">
<div class="flex justify-start flex-row-reverse">
{/* Message content */}
<div class="flex flex-col space-y-1.5">
<div class="relative mr-3 text-sm bg-blue-100 py-2 px-4 shadow rounded-xl">
<p ref={bottomRef}>{messageContent.message}</p>
</div>
<p class="text-xs text-gray-400 italic text-right mr-4">{messageContent.time}</p>
</div>
</div>
</div>
) : (
/* Recipient */
<div key={index} class="col-start-1 col-end-8 p-3 rounded-lg">
<div class="flex flex-row">
<div class="flex items-center justify-center h-10 w-10 flex-shrink-0">
<img
src={'http://localhost:8080/public/' + profilePicture}
alt="Profile picture"
class="rounded-full"
></img>
</div>
<div class="flex flex-col space-y-2">
<div class="relative ml-3 text-sm bg-white py-2 px-4 shadow rounded-xl">
<p ref={bottomRef}>{messageContent.message}</p>
</div>
<p class="text-xs text-gray-400 italic text-right ml-4">{messageContent.time}</p>
</div>
</div>
</div>
)
)
})}
</div>
</div>
{/* Input */}
<div class="flex flex-row items-center pt-3">
<input
type="text"
placeholder="Enter your message"
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyPress={(e) => {
e.key === 'Enter' && sendMessage();
}}
class="w-full h-10 px-4 text-sm rounded-3xl focus:outline-none focus:border-blue-300 focus:ring focus:ring-opacity-40 focus:ring-blue-200">
</input>
<div class="ml-6">
<button
onClick={sendMessage}
class="flex items-center justify-center h-10 w-10 rounded-full bg-gray-200 hover:bg-gray-300 text-blue-600"
>
<svg class="w-5 h-5 transform rotate-90 -mr-px"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
</svg>
</button>
</div>
</div>
{/* Back to top button */}
<div class="flex justify-center my-5">
<button
onClick={() => {document.documentElement.scrollTop = 0;}}
class="inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2"
>
Back to top
<ArrowLongUpIcon class="h-4 w-4" aria-hidden="true" />
</button>
</div>
</div>
);
};
和消息的父组件,处理其打开和关闭,请不要这个文件是非常大的,所以我删除了任何不相关的,但一些混乱仍然存在:
const socket = io('http://localhost:8080');
const roomId = [sender, profileFirstName + " " + profileLastName].sort().join('_');
const messageHandler = () => {
socket.emit('join', roomId);
setRenderMessage(!renderMessage);
};
return (
<div class="flex">
<SideBar />
<div className="flex w-screen h-auto">
<div className="flex min-w-0 flex-1 flex-col overflow-hidden">
<div className="relative z-0 flex flex-1 overflow-hidden">
<main className="relative z-0 flex-1 overflow-y-auto focus:outline-none xl:order-last">
{/* Breadcrumb */}
<article>
{/* Profile header */}
<div>
<div>
<img
className="h-32 w-full object-cover lg:h-48"
src={profile.coverImageUrl}
alt=""
/>
</div>
<div className="mx-auto max-w-5xl px-4 sm:px-6 lg:px-8">
<div className="-mt-12 sm:-mt-16 sm:flex sm:items-end sm:space-x-5">
<div className="flex">
<img
className="h-24 w-24 rounded-full ring-4 ring-white sm:h-32 sm:w-32"
src={
"http://localhost:8080/public/" +
profile.profile_picture
}
alt=""
/>
</div>
<div className="mt-6 sm:flex sm:min-w-0 sm:flex-1 sm:items-center sm:justify-end sm:space-x-6 sm:pb-1">
<div className="mt-6 min-w-0 flex-1 sm:hidden 2xl:block">
<h1 className="truncate text-2xl font-bold text-gray-900">
{profile.name}
</h1>
</div>
<div className="justify-stretch mt-6 flex flex-col space-y-3 sm:flex-row sm:space-y-0 sm:space-x-4">
<button
type="button"
onClick={messageHandler}
className="inline-flex justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2"
>
<EnvelopeIcon
className="-ml-1 mr-2 h-5 w-5 text-gray-400"
aria-hidden="true"
/>
{renderMessage ? (
<span>
Close Message
</span>
) : (
<span>Message</span>
)}
</button>
{/* <button
type="button"
className="inline-flex justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2"
>
<PhoneIcon className="-ml-1 mr-2 h-5 w-5 text-gray-400" aria-hidden="true" />
<span>Call</span>
</button> */}
</div>
</div>
</div>
<div className="mt-6 hidden min-w-0 flex-1 sm:block 2xl:hidden">
<h1 className="truncate text-2xl font-bold text-gray-900">
{profile.name}
</h1>
</div>
</div>
</div>
{/* If state is true render Messaging component */}
{renderMessage ? (
<Message
sender={sender}
recipient={profileFirstName + " " + profileLastName}
profilePicture={profileProfilePicture}
roomId={roomId}
/>
) : (
<>
{/* Description list */}
<div className="mx-auto mt-6 max-w-5xl px-4 sm:px-6 lg:px-8">
<dl className="grid grid-cols-1 gap-x-4 gap-y-8 sm:grid-cols-2">
{Object.keys(
profile.fields
).map((field) => (
<div
key={field}
className="sm:col-span-1"
>
<dt className="text-sm font-medium text-gray-500">
{field}
</dt>
<dd className="mt-1 text-sm text-gray-900">
{
profile.fields[
field
]
}
</dd>
</div>
))}
<div className="sm:col-span-2">
<dt className="text-sm font-medium text-gray-500">
About
</dt>
<dd
className="mt-1 max-w-prose space-y-5 text-sm text-gray-900"
dangerouslySetInnerHTML={{
__html: profile.about_me,
}}
/>
</div>
</dl>
</div>
{/* Team member list */}
<div className="mx-auto mt-8 max-w-5xl px-4 pb-12 sm:px-6 lg:px-8">
<h2 className="text-sm font-medium text-gray-500">
Previously worked with
</h2>
<div className="mt-1 grid grid-cols-1 gap-4 sm:grid-cols-2">
{teamPlaceHolder.map(
(person) => (
<div
key={person.handle}
className="relative flex items-center space-x-3 rounded-lg border border-gray-300 bg-white px-6 py-5 shadow-sm focus-within:ring-2 focus-within:ring-blue-600 focus-within:ring-offset-2 hover:border-gray-400"
>
<div className="flex-shrink-0">
<img
className="h-10 w-10 rounded-full"
src={
person.imageUrl
}
alt=""
/>
</div>
<div className="min-w-0 flex-1">
<a
href="#"
className="focus:outline-none"
>
<span
className="absolute inset-0"
aria-hidden="true"
/>
<p className="text-sm font-medium text-gray-900">
{
person.name
}
</p>
<p className="truncate text-sm text-gray-500">
{
person.role
}
</p>
</a>
</div>
</div>
)
)}
</div>
</div>
</>
)}
</article>
</main>
1条答案
按热度按时间sqxo8psd1#
既然您确信消息已被传输,我认为问题在于此
useEffect
依赖性这种依赖性意味着,
useEffect
内部的代码将在初始渲染时运行,之后只有当roomId
改变时才运行。由于聊天期间roomId将是相同的原语值,因此useEffect
将不运行。我认为你也应该传递
socket
对象到第一个useEffect依赖项。这是一个对象。当你点击发送按钮时,sendMessage
函数将运行。由于messages
状态将被更新,组件将重新呈现,这将创建一个全新的socket
对象。由于socket
依赖项更改,将运行第一个useEffect,您将侦听receive_message
事件。