Lifecycle Callbacks
LiveCable uses ActiveModel::Callbacks to provide lifecycle callbacks that allow you to hook into different stages of a component's lifecycle.
Available Callbacks
LiveCable provides three lifecycle events you can hook into:
connect: Triggered when the component is first subscribed to the channel (only once per component lifecycle)disconnect: Triggered when the component is unsubscribed from the channelrender: Triggered around each render and broadcast, including the initial render
Callback Methods
For each lifecycle event, you can define callbacks using standard ActiveModel callback methods:
before_connect,after_connect,around_connectbefore_disconnect,after_disconnect,around_disconnectbefore_render,after_render,around_render
Example Usage
module Live
class NotificationBell < LiveCable::Component
reactive :notifications, -> { [] }
reactive :unread_count, -> { 0 }
actions :mark_all_read
# Load data when the component first connects
after_connect :load_notifications
# Compute derived state before every render
before_render :update_unread_count
# Record when the user last viewed notifications
before_disconnect :save_last_seen
def mark_all_read
notifications.each { |n| n[:read] = true }
end
private
def load_notifications
self.notifications = current_user.notifications
.order(created_at: :desc)
.limit(20)
.as_json
end
def update_unread_count
self.unread_count = notifications.count { |n| !n[:read] }
end
def save_last_seen
current_user.update(notifications_last_seen_at: Time.current)
end
end
endCallback Execution Order
When a Component is Subscribed
- Component is instantiated
before_connectcallbacks run- Connection is established (only happens once per component lifecycle)
after_connectcallbacks runbefore_rendercallbacks run- Component is rendered and broadcast
after_rendercallbacks run
On Subsequent Updates
When state changes (action calls, reactive variable mutations):
- State changes occur
before_rendercallbacks run- Component is rendered and broadcast
after_rendercallbacks run
When a Component is Unsubscribed
before_disconnectcallbacks run- Streams are stopped and internal references cleared
after_disconnectcallbacks run- Component is removed from the connection
Connection Persistence
Important
The connect event fires once per WebSocket subscription. Within a single page, if Stimulus disconnects and reconnects a controller (for example during a parent re-render that morphs the DOM), the existing subscription is reused and connect does not fire again.
When navigating to a new page with Turbo Drive, LiveCable closes the old subscription and the page is freshly fetched from the server, so connect will fire again when the component reconnects on the new page.
This is particularly useful for:
- Subscribing to external ActionCable channels
- Loading initial data from the database
- Setting up resources that should persist for the lifetime of the component on a page
Common Use Cases
Loading Data on Connection
after_connect :load_user_preferences
private
def load_user_preferences
prefs = UserPreference.find_by(user_id: current_user.id)
return unless prefs
self.theme = prefs.theme
self.notifications_enabled = prefs.notifications_enabled
endCleaning Up Resources
after_disconnect :cleanup_resources
private
def cleanup_resources
Rails.cache.delete("component_cache_#{live_id}")
Rails.logger.info("Component #{live_id} disconnected")
endTracking Render Performance
around_render :track_render_time
private
def track_render_time
start = Time.now
yield
duration = Time.now - start
if duration > 0.1
Rails.logger.warn("Slow render: #{duration}s for #{self.class.name}")
end
endSubscribing to ActionCable Streams
Use after_connect when setting up streams so they're only created once. Streams registered via stream_from are automatically stopped when the component disconnects — no cleanup needed.
after_connect :subscribe_to_updates
private
def subscribe_to_updates
stream_from("updates_#{current_user.id}", coder: ActiveSupport::JSON) do |data|
notifications.unshift(data)
end
endBest Practices
Do
✅ Use after_connect for one-time setup (loading data, subscribing to streams) ✅ Use before_render for deriving state from reactive variables ✅ Use before_disconnect to clean up resources and save state ✅ Keep callback methods focused and single-purpose ✅ Use around_* callbacks for wrapping behavior (timing, logging)
Don't
❌ Don't perform expensive operations in before_render (it runs on every render) ❌ Don't mutate reactive variables in after_render (causes another render) ❌ Don't rely on disconnect callbacks for critical data saving (connections can drop) ❌ Don't use callbacks for business logic that should be in action methods