Live view and handle info

From ElixirBlocks
Revision as of 00:11, 29 January 2026 by Admin (talk | contribs) (Created page with "= Phoenix LiveView handle_info Guide for Web Developers = == What is handle_info? == handle_info is Phoenix LiveView's way of handling messages sent to the LiveView process from outside normal user interactions (like clicks). It's your LiveView's inbox for asynchronous events. In traditional web development, everything is request-response: user clicks, server responds, done. But LiveView processes are long-running and can receive messages from other parts of your syst...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Phoenix LiveView handle_info Guide for Web Developers

What is handle_info?

handle_info is Phoenix LiveView's way of handling messages sent to the LiveView process from outside normal user interactions (like clicks). It's your LiveView's inbox for asynchronous events.

In traditional web development, everything is request-response: user clicks, server responds, done. But LiveView processes are long-running and can receive messages from other parts of your system while they're alive.

Basic Syntax

def handle_info(message, socket) do
  # Process the message
  # Update socket state if needed
  {:noreply, socket}
end

Example 1: Timer (sending to self)

The simplest way to trigger handle_info - send a message to yourself:

defmodule AppWeb.PageLive do
  use AppWeb, :live_view

  def mount(_params, _session, socket) do
    Process.send_after(self(), :refresh, 5000)
    {:ok, socket}
  end

  def handle_info(:refresh, socket) do
    IO.inspect("Message received after 5 seconds!")
    {:noreply, socket}
  end

  def render(assigns) do
    ~H"""
    Page
    """
  end
end

Example 2: Sending Between LiveViews with PubSub

This is the recommended way to send messages between LiveViews.

In PageLive (the receiver):

defmodule AppWeb.PageLive do
  use AppWeb, :live_view

  def mount(_params, _session, socket) do
    if connected?(socket) do
      Phoenix.PubSub.subscribe(App.PubSub, "events")
    end
    {:ok, socket}
  end

  def handle_info(:my_message, socket) do
    IO.inspect("handle_info received!")
    {:noreply, socket}
  end

  def render(assigns) do
    ~H"""
    Page
    """
  end
end

In HomeLive (the sender):

defmodule AppWeb.HomeLive do
  use AppWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, socket}
  end

  def handle_event("trigger_page", _params, socket) do
    Phoenix.PubSub.broadcast(App.PubSub, "events", :my_message)
    {:noreply, socket}
  end

  def render(assigns) do
    ~H"""
    <button phx-click="trigger_page">Trigger Page handle_info</button>
    """
  end
end

Why do you need both subscribe AND broadcast?

  • Subscribe = "I want to listen to messages on the 'events' topic"
  • Broadcast = "Send this message to everyone listening to 'events'"

Without subscribe, the LiveView won't receive broadcasts. Think of it like tuning a radio to a channel - you must tune in (subscribe) before you can hear what's being transmitted (broadcast).

PubSub works with multiple LiveViews

If you have 3 PageLive tabs open, all 3 will receive the broadcast. That's a feature, not a bug.

Example 3: Process Registration (not recommended)

You can register a LiveView process with a name and send directly to it:

In PageLive:

defmodule AppWeb.PageLive do
  use AppWeb, :live_view

  def mount(_params, _session, socket) do
    if connected?(socket) do
      Process.register(self(), :page_live_process)
    end
    {:ok, socket}
  end

  def handle_info(:my_message, socket) do
    IO.inspect("handle_info received!")
    {:noreply, socket}
  end

  def render(assigns) do
    ~H"""
    Page
    """
  end
end

In HomeLive:

defmodule AppWeb.HomeLive do
  use AppWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, socket}
  end

  def handle_event("send_to_page", _params, socket) do
    send(:page_live_process, :my_message)
    {:noreply, socket}
  end

  def render(assigns) do
    ~H"""
    <button phx-click="send_to_page">Send to Page</button>
    """
  end
end

Problems with this approach:

  • Only works with ONE PageLive instance at a time
  • Crashes if name is already taken
  • Requires error handling bloat
  • PageLive must be mounted first

Use PubSub instead - it's simpler and more robust.

Common Sources of Messages

handle_info receives messages from:

  1. Timers: Process.send_after(self(), :tick, 1000)
  2. PubSub broadcasts: Phoenix.PubSub.broadcast(App.PubSub, "topic", :msg)
  3. Other processes: send(liveview_pid, :msg)
  4. Tasks: Background jobs completing
  5. GenServers: Other parts of your application

Safety: Catch-all handle_info

Always add a catch-all to prevent crashes from unexpected messages:

def handle_info(msg, socket) do
  IO.warn("Unhandled message: #{inspect(msg)}")
  {:noreply, socket}
end

Key Takeaways

  • handle_info handles asynchronous messages sent to your LiveView
  • Use send(self(), :msg) to send messages to yourself
  • Use PubSub (not process registration) to send between LiveViews
  • You must subscribe to a topic before you can receive broadcasts on that topic
  • Always include a catch-all handle_info to handle unexpected messages