LogoRobo.js

useSyncBroadcast

Send and receive ephemeral messages that don't persist.

Send fire-and-forget messages across clients. Broadcasts don't persist on the server and don't update shared state — ideal for reactions, typing indicators, sound effects, and one-off notifications.

Signature

function useSyncBroadcast<ClientData = unknown>(
	handler: (payload: unknown, context: { client: Client<ClientData> }) => void,
	key: (string | null)[]
): SyncBroadcastResult<ClientData>
function useSyncBroadcast(
	handler: (payload, context) => void,
	key: (string | null)[]
): SyncBroadcastResult<ClientData>

Parameters

ParameterTypeDescription
handler(payload, { client }) => voidCallback invoked on incoming broadcasts
key(string | null)[]Room key scoping which broadcasts to receive

Return value

FieldTypeDescription
broadcast(payload: unknown) => voidSend to all clients watching this key
send(clientId: string, payload: unknown) => voidSend to a specific client
contextSyncContext<ClientData>Full sync context

Basic usage

A typing indicator using broadcasts.

import { useSyncBroadcast } from '@robojs/sync'

function Chat() {
	const [typingUsers, setTypingUsers] = useState<string[]>([])

	const { broadcast } = useSyncBroadcast((payload, { client }) => {
		if (payload.type === 'typing') {
			setTypingUsers((prev) => [...new Set([...prev, client.id])])
			setTimeout(() => {
				setTypingUsers((prev) => prev.filter((id) => id !== client.id))
			}, 2000)
		}
	}, ['chat', roomId])

	return (
		<div>
			<input onKeyDown={() => broadcast({ type: 'typing' })} />
			{typingUsers.length > 0 && <p>{typingUsers.length} typing...</p>}
		</div>
	)
}
import { useSyncBroadcast } from '@robojs/sync'

function Chat() {
	const [typingUsers, setTypingUsers] = useState([])

	const { broadcast } = useSyncBroadcast((payload, { client }) => {
		if (payload.type === 'typing') {
			setTypingUsers((prev) => [...new Set([...prev, client.id])])
			setTimeout(() => {
				setTypingUsers((prev) => prev.filter((id) => id !== client.id))
			}, 2000)
		}
	}, ['chat', roomId])

	return (
		<div>
			<input onKeyDown={() => broadcast({ type: 'typing' })} />
			{typingUsers.length > 0 && <p>{typingUsers.length} typing...</p>}
		</div>
	)
}

Sending to a specific client

const { send, context } = useSyncBroadcast(handler, ['game', roomId])

// Send private message to one client
send(targetClientId, { type: 'whisper', text: 'hello' })
const { send, context } = useSyncBroadcast(handler, ['game', roomId])

// Send private message to one client
send(targetClientId, { type: 'whisper', text: 'hello' })

Server broadcasts

Server-side code can also send broadcasts via the Server Zone API. These arrive with client.id === '__server__'.

useSyncBroadcast((payload, { client }) => {
	if (client.id === '__server__') {
		console.log('Server notification:', payload)
	}
}, ['game', roomId])
useSyncBroadcast((payload, { client }) => {
	if (client.id === '__server__') {
		console.log('Server notification:', payload)
	}
}, ['game', roomId])

Broadcast vs state

useSyncState persists state on the server and syncs it to all clients. Late joiners get the current state.

useSyncBroadcast sends one-off messages. Late joiners miss past broadcasts. No state is stored on the server.

Use broadcasts for: reactions, typing indicators, sound triggers, cursor positions (via useSyncCursor), and notifications.

Next Steps

On this page