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!'
})