This guide covers working with messages inside a conversation: loading the message history, sending new messages, editing and deleting messages, and toggling emoji reactions.
Loading Messages
useLiveChatMessages fetches paginated messages for a conversation. Messages are stored in Redux and kept in sync by the ChatProvider socket.
useChatMessages was renamed to useLiveChatMessages. The old name still works as a deprecated alias.
import { useLiveChatMessages } from "@sublay/react-js" ;
function MessageList ({ conversationId } : { conversationId : string }) {
const { messages , loading , hasMore , loadOlder } = useLiveChatMessages ({
conversationId ,
});
return (
< div >
{ hasMore && (
< button onClick = { loadOlder } disabled = { loading } >
Load older messages
</ button >
) }
{ messages . map (( msg ) => (
< div key = { msg . id } >
< strong > { msg . user ?. name } </ strong > : { msg . content }
</ div >
)) }
</ div >
);
}
Messages are sorted oldest-first in the returned array. loadOlder fetches messages older than the oldest currently loaded.
To include attached files in the response, pass includeFiles: true:
const { messages } = useLiveChatMessages ({ conversationId , includeFiles: true });
See useLiveChatMessages .
Filtered / read-only queries
useLiveChatMessages is the live conversation stream and intentionally takes no filters. To fetch a filtered or read-only list of messages — for example, only messages that have replies — use useFetchManyChatMessagesWrapper , which keeps results in local state and never receives live socket traffic:
import { useFetchManyChatMessagesWrapper } from "@sublay/react-js" ;
const { messages , loading , hasMore , loadMore , refetch } =
useFetchManyChatMessagesWrapper ({
conversationId ,
filters: { hasReplies: true },
});
See useFetchManyChatMessages .
Sending Messages
useSendMessage returns an async function that sends a message and performs an optimistic insert — the message appears immediately in the UI with a temporary ID, then the temporary entry is replaced by the server-confirmed message.
import { useSendMessage } from "@sublay/react-js" ;
function MessageInput ({ conversationId } : { conversationId : string }) {
const send = useSendMessage ({ conversationId });
const [ text , setText ] = useState ( "" );
const handleSend = async () => {
if ( ! text . trim ()) return ;
await send ({ content: text });
setText ( "" );
};
return (
< div >
< input value = { text } onChange = { ( e ) => setText ( e . target . value ) } />
< button onClick = { handleSend } > Send </ button >
</ div >
);
}
Message Content Options
useSendMessage accepts a rich set of parameters:
Parameter Type Description contentstringPlain text content gifGifDataGIF attachment mentionsMention[]User mentions embedded in the message metadataRecord<string, any>Arbitrary key-value data quotedMessageIdstring | nullID of the message being quoted/replied to parentMessageIdstring | nullID of the parent message (for thread replies) filesFile[]File attachments (triggers multipart upload)
Sending with Files
When files is provided, the hook automatically switches to a multipart form upload:
const handleSendWithFile = async ( file : File ) => {
await send ({
content: "Check this out" ,
files: [ file ],
});
};
See useSendMessage .
Editing Messages
useEditMessage returns a function that takes conversationId, messageId, and updated content fields. The Redux store is updated immediately on success.
import { useEditMessage } from "@sublay/react-js" ;
function EditableMessage ({ conversationId , messageId }) {
const edit = useEditMessage ();
const handleEdit = async ( newContent : string ) => {
await edit ({ conversationId , messageId , content: newContent });
};
// ...
}
See useEditMessage .
Deleting Messages
useDeleteMessage performs a soft delete. The message is removed from the local Redux store immediately; on the server, it is soft-deleted (content cleared, userDeletedAt set).
import { useDeleteMessage } from "@sublay/react-js" ;
function MessageActions ({ conversationId , messageId }) {
const deleteMsg = useDeleteMessage ();
return (
< button onClick = { () => deleteMsg ({ conversationId , messageId }) } >
Delete
</ button >
);
}
See useDeleteMessage .
Reactions
useToggleReaction adds or removes an emoji reaction on a message. The response includes updated reactionCounts and userReactions:
import { useToggleReaction } from "@sublay/react-js" ;
function ReactionBar ({ conversationId , messageId , reactionCounts , userReactions }) {
const toggle = useToggleReaction ();
return (
< div >
{ [ "👍" , "❤️" , "😂" ]. map (( emoji ) => (
< button
key = { emoji }
onClick = { () => toggle ({ conversationId , messageId , emoji }) }
style = { { fontWeight: userReactions . includes ( emoji ) ? "bold" : "normal" } }
>
{ emoji } { reactionCounts [ emoji ] ?? 0 }
</ button >
)) }
</ div >
);
}
See useToggleReaction .
Next Steps
Real-time Typing indicators, unread counts, and read receipts
Threads Threaded replies on messages