Skip to main content

Advanced usage

Custom Headers & Authentication
// Static headers
const actionCable = ActionCable.createConsumer('ws://localhost:3000/cable', {
'Authorization': 'Bearer token123'
})

// Dynamic headers (re-evaluated on each connection)
const actionCable = ActionCable.createConsumer('ws://localhost:3000/cable', () => ({
'Authorization': `Bearer ${getAuthToken()}`
}))
Preventing Duplicate Connections

Use getOrCreateConsumer to prevent duplicate connections during hot reloads:

// ❌ Creates new connection every time
const actionCable = ActionCable.createConsumer('ws://localhost:3000/cable')

// ✅ Reuses existing connection
const actionCable = ActionCable.getOrCreateConsumer('ws://localhost:3000/cable')
Error Handling
channel.on('error', ({ message, event }) => {
console.warn('Connection error:', message)
// Handle: no internet, wrong URL, server down, auth failure
// `event` is the original platform event, if you need it
})

// React Native reports *why* a socket dropped on the close event
channel.on('disconnected', ({ willAttemptReconnect, reason }) => {
console.log(reason, willAttemptReconnect ? '- retrying' : '- gave up')
})
React Hook Example
function useActionCable(channelName: string, params: Record<string, unknown>) {
const [connected, setConnected] = useState(false)

useEffect(() => {
const channel = cable.setChannel(
channelName,
actionCable.subscriptions.create({ channel: channelName, ...params })
)

channel
.on('connected', () => setConnected(true))
.on('disconnected', () => setConnected(false))
.on('received', handleReceived)

return () => {
channel.removeListener('received', handleReceived)
channel.unsubscribe()
delete cable.channels[channelName]
}
}, [channelName])

return { connected, channel: cable.channel(channelName) }
}
Rails style channel mixins

subscriptions.create accepts an optional mixin of callbacks, exactly like Rails ActionCable, which makes existing Rails channel code portable:

const channel = actionCable.subscriptions.create({ channel: 'ChatChannel', roomId: 1 }, {
connected ({ reconnected }) { console.log('Connected!', reconnected) },
disconnected ({ willAttemptReconnect }) { console.log('Disconnected', willAttemptReconnect) },
received (data) { console.log('Received:', data) },

speak (text: string) { this.perform('speak', { text }) },
})

channel.speak('Hello!')

A mixin replaces the event emitter callbacks it defines - use either style, not both for the same event.

Custom Action Events

Messages with data.action attribute are emitted as separate events:

# Rails sends:
{ action: 'speak', text: 'hello!' }
// React Native receives:
channel.on('speak', (data) => {
console.log(data.text) // 'hello!'
})