Pub/Sub

Publish custom named events to a channel. All subscribers receive them in real time. No server code required for basic pub/sub.

Channel naming

Use a path with a slash for custom channels. This bypasses ChangeTracker and uses pure WebSocket pub/sub:

const channel = realtime.channel('todos/shared-workspace')
// or:
const channel = realtime.channel('chat/general')
const channel = realtime.channel('game/room-42')

Publish an event

channel.publish('todo:created', {
  id: '123',
  text: 'Buy groceries',
  done: false,
})

All other subscribers on todos/shared-workspace receive this event immediately.

Listen for events

channel
  .on('todo:created', ({ data }) => {
    setTodos(prev => [...prev, data])
  })
  .on('todo:toggled', ({ data }) => {
    setTodos(prev => prev.map(t => t.id === data.id ? data : t))
  })
  .on('todo:deleted', ({ data }) => {
    setTodos(prev => prev.filter(t => t.id !== data.id))
  })
  .subscribe()

Avoid echo on your own events

Use a client ID to skip events you published yourself:

const clientId = useRef(Math.random().toString(36).slice(2))
 
channel.on('todo:created', ({ data, userId }) => {
  if (userId === clientId.current) return // skip own event
  setTodos(prev => [...prev, data])
})
 
// Pass your clientId so the server includes it in userId
channel.publish('todo:created', todo)

Persist events for history

Pass { persist: true } to store the message in the database for later retrieval:

channel.publish('message', {
  text: 'Hello everyone!',
  userId: user.id,
}, { persist: true })

Retrieve history with channel.getHistory() — see Message History.

Server-side pub/sub

Your Workers/Node.js server can also publish to channels:

// In your Worker handler
sdk.socket.emit('todo:created', newTodo, 'todos/shared-workspace')

This is useful when you want to validate or transform data before broadcasting.

Complete example

import { useAerostack } from '@aerostack/react'
import { useEffect, useRef, useState } from 'react'
 
function CollaborativeList() {
  const { realtime } = useAerostack()
  const [items, setItems] = useState([])
  const myId = useRef(Math.random().toString(36).slice(2))
  const channelRef = useRef(null)
 
  useEffect(() => {
    const ch = realtime.channel('list/shared')
    channelRef.current = ch
 
    ch
      .on('item:added', ({ data, userId }) => {
        if (userId === myId.current) return
        setItems(prev => [...prev, data])
      })
      .subscribe()
 
    return () => ch.unsubscribe()
  }, [realtime])
 
  const addItem = (text) => {
    const item = { id: Date.now(), text }
    setItems(prev => [...prev, item])                    // optimistic
    channelRef.current.publish('item:added', item)       // broadcast to peers
  }
 
  return (
    <>
      <button onClick={() => addItem('New item')}>Add</button>
      <ul>{items.map(i => <li key={i.id}>{i.text}</li>)}</ul>
    </>
  )
}

See the Collaborative Todos example for a complete working implementation with toggle, delete, and presence.