Phoenix LiveView
Rich, real-time UIs rendered on the server; the browser receives minimal diffs over a WebSocket.
46.1 A counter LiveView
defmodule BlogWeb.CounterLive do
use BlogWeb, :live_view
def mount(_params, _session, socket), do: {:ok, assign(socket, count: 0)}
def handle_event("inc", _params, socket), do: {:noreply, update(socket, :count, &(&1 + 1))}
def handle_event("dec", _params, socket), do: {:noreply, update(socket, :count, &(&1 - 1))}
def render(assigns) do
~H"""
<h1>Count: {@count}</h1>
<button phx-click="dec">-</button>
<button phx-click="inc">+</button>
"""
end
end46.2 Lifecycle
HTTP request → mount/3 + render/1 → static HTML (SEO-friendly).
Client connects via WebSocket → mount/3 again (connected) → stateful process.
Events (phx-click, phx-submit, phx-change, phx-keydown, phx-blur) → handle_event/3.
handle_params/3 on URL changes (push_patch, <.link patch=...>).
handle_info/2 for PubSub/process messages → real-time updates.
connected?(socket) distinguishes the two mounts (subscribe to PubSub only when connected).
46.3 Forms & validation
def mount(_, _, socket), do: {:ok, assign(socket, form: to_form(Posts.change_post(%Post{})))}
def handle_event("validate", %{"post" => p}, socket) do
cs = Posts.change_post(%Post{}, p) |> Map.put(:action, :validate)
{:noreply, assign(socket, form: to_form(cs))}
end
def handle_event("save", %{"post" => p}, socket) do
case Posts.create_post(p) do
{:ok, post} -> {:noreply, push_navigate(socket, to: ~p"/posts/#{post}")}
{:error, cs} -> {:noreply, assign(socket, form: to_form(cs))}
end
end<.form for={@form} phx-change="validate" phx-submit="save">
<.input field={@form[:title]} label="Title" />
<.button>Save</.button>
</.form>46.4 Advanced LiveView
Streams (stream/3, stream_insert/3) — huge collections without keeping them in memory.
LiveComponents — stateful sub-components (use Phoenix.LiveComponent).
Async assigns — assign_async/3, start_async/3, <.async_result>.
Uploads — allow_upload/3, live_file_input, direct-to-S3.
JS commands — JS.show/1, JS.toggle/1, JS.push/2 without custom JS.
Hooks — phx-hook for custom client JS.
on_mount hooks for auth across LiveViews; live_session.
Testing with Phoenix.LiveViewTest: live/2, render_click/2, render_submit/2.