🚀 Quick Start
Learn how to build your first real-time chat application with XHub Chat in just a few minutes.
Overview
In this guide, you'll learn how to:
- Set up the XHub Chat client with Provider
- Get Room list and paginate rooms
- Show messages with pagination
- Send and receive messages in real-time
- Handle reactions and threads
⏱️ This guide takes approximately 10 minutes to complete.
--Note--
- Tất cả message được xem là 1 đối tượng event
XHubChatEvent. Để lấy thông tin từ message xem các api trong đối tượngXHubChatEvent - Mỗi room sẽ có 1 timeline-set chứa nhiều timeline nhỏ, mỗi timeline sẽ chứa các event (message, reaction, etc..)
- Room sẽ có 2 dạng là phòng chat và bài post, mỗi dạng sẽ có UI và tính năng khác nhau tuỳ theo mục đích sử dụng, sử dụng thuộc tính
room.roomData.categoryđể phân biệt. Các tính năng like/unlike chỉ thực hiện được trong các phòng là bài Post. - Sử dụng
goIntoRoom()trong đối tượngroomkhi vào phòng để đánh dấu đã đọc, sử dụnggoOutRoom()khi rời phòng để cập nhật trạng thái online/offline. Bắt buộc - Khi tải danh sách các phòng thì các tin nhắn trong phòng chưa được load, chỉ có 1 tin nhắn cuối cùng trong phòng, khi nào cần load thêm tin nhắn thì cần gọi hàm
paginatetronguseTimelineđể load tin nhắn trong phòng đó.
Step 1: Install Packages
First, install the required packages:
- npm
- pnpm
- yarn
- bun
npm install @xhub-chat/react
pnpm add @xhub-chat/react
yarn add @xhub-chat/react
bun add @xhub-chat/react
Step 2: Create Provider Wrapper
Create a provider component that wraps the SDK provider with your configuration:
import type { ICreateClientOpts } from '@xhub-chat/react';
import { XHubChatProvider as XHubChatProviderSDK } from '@xhub-chat/react';
export default function XHubChatProvider({ children }: { children: React.ReactNode }) {
const clientOptions: ICreateClientOpts = {
clientParams: { api_key: 'YOUR_API_KEY' },
baseUrl: 'https://your-server.com/',
realtime: {
channels: ['online:index', `user:YOUR_USER_ID`],
url: 'wss://your-websocket-server.com/connection/websocket',
token: 'YOUR_REALTIME_TOKEN', // <- YOUR_ACCESS_TOKEN
},
userId: 'YOUR_USER_ID',
deviceId: 'YOUR_DEVICE_ID',
accessToken: 'YOUR_ACCESS_TOKEN',
};
return (
<XHubChatProviderSDK
// (Optional) Enable IndexedDB for offline support
workerFactory={indexeddbWorkerFactory}
clientOptions={clientOptions}
startOptions={{ initialSyncLimit: 10 }}
>
{children}
</XHubChatProviderSDK>
);
}
See the Configuration Guide for all available options.
Wrap your application with the XHubChatProvider:
import XHubChatProvider from '@/components/providers/XHubChatProvider';
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html suppressHydrationWarning>
<body>
<XHubChatProvider>
{children}
</XHubChatProvider>
</body>
</html>
);
}
Step 3: Get Room list and paginate rooms
Create a component to display chat rooms:
import { useRooms } from '@xhub-chat/react';
import type { Room } from '@xhub-chat/react';
interface RoomListProps {
selectedRoomId: string | null;
onRoomSelect: (roomId: string) => void;
}
export function RoomList({ selectedRoomId, onRoomSelect }: RoomListProps) {
const { rooms, canPaginate, paginate, fetching, isLoading } = useRooms();
if (isLoading) {
return <p>Loading rooms...</p>;
}
return (
<div className="rooms-list">
{rooms.map((room) => (
<button
key={room.roomId}
className={`room-item ${selectedRoomId === room.roomId ? 'selected' : ''}`}
onClick={() => {
onRoomSelect(room.roomId);
// TODO: Mark room as entered
room.goIntoRoom();
}}
>
<div className="room-name">{room.name || room.roomId}</div>
<div className="room-meta">
{room.summary?.getDescription()}
</div>
{/* Unread badge */}
{room.getUnreadNotificationCount() > 0 && (
<div className="unread-badge">
{room.getUnreadNotificationCount()}
</div>
)}
</button>
))}
{/* Load more rooms */}
{canPaginate && (
fetching ? (
<Loader />
) : (
<button onClick={() => paginate(20)}>Load More</button>
)
)}
</div>
);
}
Use Room.getCategory() to specialize room rendering based on its type (Chat room or Post). RoomCategory
Step 4: Display Messages with Pagination, Send message in chat room
Show messages from a room with pagination and send new messages:
- In Message List, use
useTimelineto get messages and pagination functions. - With chat room, and message just can send and receive text message. Not support reply and reaction.
import { useTimeline, Direction } from '@xhub-chat/react';
import type { Room } from '@xhub-chat/react';
import { Message } from './Message';
interface MessageListProps {
room: Room;
}
export function MessageList({ room }: MessageListProps) {
const {
events,
paginate,
sendTextMessage,
canPaginateBackwards,
isPaginatingBackwards,
} = useTimeline({
roomId: room.roomId,
timelineSet: room.getUnfilteredTimelineSet()
});
const handlePaginate = () => {
if (canPaginateBackwards && !isPaginatingBackwards) {
paginate(Direction.Backward, 50, true, 50);
}
};
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
sendTextMessage(textValue);
setTextValue('');
};
/**
* Messages in room not load when init room,
* need first call to get message in room
*/
useEffect(() => handlePaginate(), []);
return (
<div className="messages-list">
{/* Sort messages by timestamp (newest at bottom) */}
{events
.sort((a, b) => b.getTs() - a.getTs())
.map((event) => (
<Message key={event.id} event={event} />
))}
{/* Load older messages */}
{canPaginateBackwards && (
isPaginatingBackwards ? (
<Loader />
) : (
<button onClick={handlePaginate}>
Load More
</button>
)
)}
<form onSubmit={onSubmit}>
<input
value={textValue}
onChange={e => setTextValue(e.target.value)}
/>
<button type="submit">Send</button>
</form>
</div>
);
}
Step 5: Create Message Component
Build a message component:
import type { XHubChatEvent } from '@xhub-chat/react';
import { useXHubChat } from '@xhub-chat/react';
interface MessageProps {
event: XHubChatEvent;
}
export function Message({ event, onReply, onReact, reactions }: MessageProps) {
const { client } = useXHubChat();
// Or can use `client.getUserId()` if you provided userId in provider
const isOwner = event.sender?.userId === `$your-user-id`;
/**
* Get sending status: `SENDING -> SENT -> null`
* - SENDING -> Start call api to server
* - SENT -> Received ack from server (not confirmed by server)
* - `null` -> Send successfully (Common case for normal message)
*/
const isSending = event.getAssociatedStatus() === EventStatus.SENDING;
return (
<div className={`message ${isOwner ? 'message-own' : ''}`}>
{/** Content */}
<div className="message-content">
{event.getContent()?.text || '[No content]'}
</div>
<div className="message-footer">
{/** Timestamp */}
<span className="message-time">
{new Date(event.getTs()).toLocaleString()}
</span>
{/* Sending status */}
{isSending ? <Loader /> : <CheckIcon />}
</div>
</div>
);
}
Step 6: Get contacts and create direct message room
import { useContacts } from '@xhub-chat/react';
export default function ContactList() {
const { contacts, createDirectRoomWithContact } = useContacts();
return (
<div className="status-card" style={{ width: '20%', height: '100%', overflowY: 'auto' }}>
<h3>Contacts</h3>
{contacts.map(contact => (
<div
onClick={async () => {
const room = await createDirectRoomWithContact(contact.channel_slug);
// Do something with the created room (navigate to it, etc.)
}}
>
<div className="contact-name">{contact.displayName}</div>
<div className="contact-presence" style={{ fontSize: 12, color: '#a7a7a7ff' }}>
{contact.isOnline() ? 'Online' : 'Offline'}
</div>
</div>
))}
</div>
);
}
🎉 Congratulations
You've successfully created a full-featured chat application with XHub Chat! Your app now supports:
- ✅ Display chat rooms with unread counts
- ✅ Real-time message updates
- ✅ Message pagination (load older messages)
- ✅ Send and receive messages
- ✅ Reply to messages (threads)
- ✅ Reactions (like/unlike messages)
- ✅ Room pagination (load more rooms)
📚 Next Steps
Now that you have a working chat application, you can:
- Explore all Features - Learn about posts, comments, and more
- Read the API Reference - Discover all available methods
- Check out Advanced Guides - Deep dive into architecture
- View Complete Examples - See production-ready implementations
💡 Tips
- Use
goIntoRoom()when entering a room to mark it as read - Use
goOutRoom()when leaving to update presence - Enable
workerFactoryfor better performance with IndexedDB - Set
initialSyncLimitto control how many rooms load initially - Use
Direction.Backwardfor loading older messages
The complete working code is available in the playground app on GitHub.
- ✅ Show messages in a room
- ✅ Send new messages
- ✅ Load more messages with pagination
What's Next?
Now that you have a working chat app, explore more features:
Essential Features
- 🔐 Authentication - Secure your chat app
- 💬 Message Reactions - Add emoji reactions
- 🧵 Message Threading - Support threaded conversations
- 📎 File Attachments - Send images and files
Advanced Topics
- 🔌 Event System - Listen to real-time events
- 💾 Offline Support - IndexedDB caching
- ⚡ Performance Optimization - Best practices
API Reference
- 📘 React Hooks API - Complete hook reference
- 📗 Core API - Client methods and classes
- 📙 Type Definitions - TypeScript types
Need Help?
- 📖 Read the Core Concepts
- 💡 Check out Examples
- 🐛 Report an issue
- 💬 Ask a question