💬 Send & Receive Messages
Gửi tin nhắn văn bản và nhận tin nhắn real-time trong phòng chat.
Core Package (@xhub-chat/core)
Send Text Message
import { createClient } from '@xhub-chat/core';
const client = createClient({
baseUrl: 'https://your-server.com',
accessToken: 'your-access-token',
userId: '@user:server.com',
});
await client.startClient();
// Send a text message
const roomId = '!roomId:server.com';
const message = 'Hello, World!';
await client.sendTextMessage(roomId, message);
Receive Messages
import { RoomEvent } from '@xhub-chat/core';
const room = client.getRoom(roomId);
if (room) {
// Listen for new messages
room.on(RoomEvent.Timeline, (event, room, toStartOfTimeline) => {
if (event.getType() === 'm.room.message' && !toStartOfTimeline) {
console.log('New message:', {
sender: event.getSender(),
content: event.getContent().body,
timestamp: event.getDate(),
});
}
});
}
Get Timeline Events
// Get all messages in the room
const timeline = room.getLiveTimeline();
const events = timeline.getEvents();
events.forEach(event => {
if (event.getType() === 'm.room.message') {
console.log(event.getContent().body);
}
});
Pagination (Load More Messages)
import { EventTimeline } from '@xhub-chat/core';
const timeline = room.getLiveTimeline();
// Load older messages
await client.paginateEventTimeline(timeline, {
backwards: true,
limit: 20,
});
// Get updated events
const allEvents = timeline.getEvents();
Resend Failed Messages
import { EventStatus } from '@xhub-chat/core';
// Find failed messages
const pendingEvents = room.getPendingEvents();
const failedEvent = pendingEvents.find(e =>
e.status === EventStatus.NOT_SENT
);
if (failedEvent) {
// Resend the event
await client.resendEvent(failedEvent, room);
}
React Package (@xhub-chat/react)
Send Messages
import { useXHubChat, useRoom } from '@xhub-chat/react';
import { useState } from 'react';
function MessageInput({ roomId }: { roomId: string }) {
const client = useXHubChat();
const room = useRoom(roomId);
const [message, setMessage] = useState('');
const [sending, setSending] = useState(false);
const handleSend = async () => {
if (!client || !message.trim()) return;
setSending(true);
try {
await client.sendTextMessage(roomId, message);
setMessage('');
} catch (error) {
console.error('Failed to send:', error);
} finally {
setSending(false);
}
};
return (
<div>
<input
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSend()}
disabled={sending}
placeholder="Type a message..."
/>
<button onClick={handleSend} disabled={sending}>
{sending ? 'Sending...' : 'Send'}
</button>
</div>
);
}
Receive & Display Messages
import { useTimeline } from '@xhub-chat/react';
function MessageList({ roomId }: { roomId: string }) {
const { events, loading } = useTimeline(roomId);
if (loading) return <div>Loading messages...</div>;
return (
<div className="message-list">
{events.map(event => {
if (event.getType() !== 'm.room.message') return null;
return (
<div key={event.getId()} className="message">
<strong>{event.getSender()}</strong>
<p>{event.getContent().body}</p>
<time>{event.getDate()?.toLocaleString()}</time>
</div>
);
})}
</div>
);
}
Complete Chat Component
import { useTimeline, useXHubChat } from '@xhub-chat/react';
import { useState, useRef, useEffect } from 'react';
function ChatRoom({ roomId }: { roomId: string }) {
const client = useXHubChat();
const {
events,
loading,
paginate,
canPaginateBackwards
} = useTimeline(roomId);
const [message, setMessage] = useState('');
const messagesEndRef = useRef<HTMLDivElement>(null);
// Auto-scroll to bottom
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [events]);
const handleSend = async (e: React.FormEvent) => {
e.preventDefault();
if (!client || !message.trim()) return;
await client.sendTextMessage(roomId, message);
setMessage('');
};
const loadMore = async () => {
await paginate({ backwards: true, limit: 20 });
};
return (
<div className="chat-room">
{canPaginateBackwards && (
<button onClick={loadMore}>Load older messages</button>
)}
<div className="messages">
{events.map(event => (
<Message key={event.getId()} event={event} />
))}
<div ref={messagesEndRef} />
</div>
<form onSubmit={handleSend}>
<input
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Type a message..."
/>
<button type="submit">Send</button>
</form>
</div>
);
}
function Message({ event }: { event: XHubChatEvent }) {
if (event.getType() !== 'm.room.message') return null;
return (
<div className="message">
<strong>{event.getSender()}</strong>
<p>{event.getContent().body}</p>
</div>
);
}
API Reference
Send Methods
sendTextMessage(roomId: string, text: string): Promise<void>resendEvent(event: XHubChatEvent, room: Room): Promise<void>
Timeline Methods
getLiveTimeline(): EventTimelinepaginateEventTimeline(timeline, opts): Promise<boolean>
Event Properties
interface XHubChatEvent {
getId(): string;
getType(): string;
getSender(): string | null;
getContent(): any;
getDate(): Date | null;
status: EventStatus;
}