Skip to content

Commit 4e30b7c

Browse files
committed
Added docs section for handling self published message to messages.kt
1 parent 7611b9d commit 4e30b7c

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed

src/pages/docs/chat/rooms/messages.mdx

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,146 @@ fun MyComponent(room: Room) {
228228
```
229229
</Code>
230230

231+
### Handle self-published messages <a id="self-published-messages"/>
232+
233+
<Aside data-type='important'>
234+
When you send a message using `send()`, the server echoes it back to all subscribers in the room, including the sender. If your application adds the message to the UI immediately after calling `send()` and also appends it when received via `subscribe()`, the message will appear twice.
235+
236+
To avoid this, use one of the following approaches:
237+
238+
**Approach 1: Only render messages from the subscription.** Do not add the message to the UI when calling `send()`. Instead, rely solely on the subscription listener to display all messages, including your own. This is the simplest approach and ensures consistency with the server's message ordering and `serial` assignment.
239+
240+
**Approach 2: Use `serial` to deduplicate.** If you want optimistic UI updates (displaying the message immediately on send for a more responsive experience), use the `serial` property of the message returned by `send()` to filter out the duplicate when it arrives via the subscription. When a new message event is received, check whether a message with the same `serial` already exists in your local list before adding it.
241+
</Aside>
242+
243+
The following example demonstrates approach 2, using `serial`-based deduplication to prevent duplicate messages:
244+
245+
<Code>
246+
```javascript
247+
import { ChatMessageEventType } from '@ably/chat';
248+
const messages = [];
249+
250+
// Subscribe to incoming messages
251+
room.messages.subscribe((event) => {
252+
if (event.type === ChatMessageEventType.Created) {
253+
// Only add the message if it doesn't already exist in the list
254+
const exists = messages.some((msg) => msg.serial === event.message.serial);
255+
if (!exists) {
256+
messages.push(event.message);
257+
}
258+
}
259+
});
260+
261+
// Send a message and optimistically add it to the list
262+
const message = await room.messages.send({ text: 'hello' });
263+
messages.push(message);
264+
```
265+
266+
```react
267+
import { useState, useCallback } from 'react';
268+
import { ChatMessageEventType } from '@ably/chat';
269+
import { useMessages } from '@ably/chat/react';
270+
271+
const MyComponent = () => {
272+
const [messages, setMessages] = useState([]);
273+
274+
const { sendMessage } = useMessages({
275+
listener: (event) => {
276+
if (event.type === ChatMessageEventType.Created) {
277+
setMessages((prev) => {
278+
// Only add the message if it doesn't already exist in the list
279+
if (prev.some((msg) => msg.serial === event.message.serial)) {
280+
return prev;
281+
}
282+
return [...prev, event.message];
283+
});
284+
}
285+
},
286+
});
287+
288+
const handleSend = useCallback(async () => {
289+
const message = await sendMessage({ text: 'hello' });
290+
setMessages((prev) => [...prev, message]);
291+
}, [sendMessage]);
292+
293+
return <div>...</div>;
294+
};
295+
```
296+
297+
```swift
298+
var messages: [Message] = []
299+
let messagesSubscription = try await room.messages.subscribe()
300+
301+
// Subscribe to incoming messages
302+
Task {
303+
for await message in messagesSubscription {
304+
// Only add the message if it doesn't already exist in the list
305+
if !messages.contains(where: { $0.serial == message.serial }) {
306+
messages.append(message)
307+
}
308+
}
309+
}
310+
311+
// Send a message and optimistically add it to the list
312+
let sentMessage = try await room.messages.send(withParams: .init(text: "hello"))
313+
messages.append(sentMessage)
314+
```
315+
316+
```kotlin
317+
val messages = mutableListOf<Message>()
318+
319+
// Subscribe to incoming messages
320+
val subscription = room.messages.subscribe { event ->
321+
if (event.type == ChatMessageEventType.Created) {
322+
// Only add the message if it doesn't already exist in the list
323+
val exists = messages.any { it.serial == event.message.serial }
324+
if (!exists) {
325+
messages.add(event.message)
326+
}
327+
}
328+
}
329+
330+
// Send a message and optimistically add it to the list
331+
val sentMessage = room.messages.send(text = "hello")
332+
messages.add(sentMessage)
333+
```
334+
335+
```android
336+
import androidx.compose.runtime.*
337+
import com.ably.chat.ChatMessageEventType
338+
import com.ably.chat.Message
339+
import com.ably.chat.Room
340+
import com.ably.chat.asFlow
341+
import kotlinx.coroutines.launch
342+
343+
@Composable
344+
fun MyComponent(room: Room) {
345+
var messages by remember { mutableStateOf<List<Message>>(emptyList()) }
346+
val coroutineScope = rememberCoroutineScope()
347+
348+
// Subscribe to incoming messages
349+
LaunchedEffect(room) {
350+
room.messages.asFlow().collect { event ->
351+
if (event.type == ChatMessageEventType.Created) {
352+
// Only add the message if it doesn't already exist in the list
353+
if (messages.none { it.serial == event.message.serial }) {
354+
messages = messages + event.message
355+
}
356+
}
357+
}
358+
}
359+
360+
// Send a message and optimistically add it to the list
361+
fun sendMessage(text: String) {
362+
coroutineScope.launch {
363+
val sentMessage = room.messages.send(text = text)
364+
messages = messages + sentMessage
365+
}
366+
}
367+
}
368+
```
369+
</Code>
370+
231371
## Get a single message <a id="get-by-serial"/>
232372

233373
<If lang="javascript,swift,kotlin,android">

0 commit comments

Comments
 (0)