Phoenix LiveView Philosophy
LiveView keeps state on the server and sends only HTML diffs over WebSocket. No JSON API, no client state management needed.
Basic Counter LiveView
defmodule MyAppWeb.CounterLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, count: 0)}
end
def render(assigns) do
~H"""
<div>
<h1>Count: <%= @count %></h1>
<button phx-click="inc">+</button>
<button phx-click="dec">-</button>
</div>
"""
end
def handle_event("inc", _params, socket) do
{:noreply, update(socket, :count, &(&1 + 1))}
end
def handle_event("dec", _params, socket) do
{:noreply, update(socket, :count, &(&1 - 1))}
end
end
Real-Time Chat with PubSub
defmodule MyAppWeb.ChatLive do
use MyAppWeb, :live_view
def mount(%{"room_id" => room_id}, _session, socket) do
if connected?(socket) do
Phoenix.PubSub.subscribe(MyApp.PubSub, "room:" <> room_id)
end
{:ok, assign(socket, messages: [], room_id: room_id)}
end
def handle_event("send", %{"text" => text}, socket) do
msg = %{text: text, user: socket.assigns.current_user}
Phoenix.PubSub.broadcast(MyApp.PubSub, "room:" <> socket.assigns.room_id, {:msg, msg})
{:noreply, socket}
end
def handle_info({:msg, msg}, socket) do
{:noreply, update(socket, :messages, &(&1 ++ [msg]))}
end
end
Live Components
defmodule MyAppWeb.CardComponent do
use MyAppWeb, :live_component
def render(assigns) do
~H"""
<div id={"card-" <> @item.id}>
<h3><%= @item.title %></h3>
<button phx-click="like" phx-target={@myself}>Like (<%= @likes %>)</button>
</div>
"""
end
def handle_event("like", _params, socket) do
{:noreply, update(socket, :likes, &(&1 + 1))}
end
end
JS Hooks for Client-Side Interop
// app.js
let Hooks = {}
Hooks.Chart = {
mounted() {
this.chart = new Chart(this.el, { type: 'line', data: JSON.parse(this.el.dataset.values) })
this.handleEvent("update_chart", ({values}) => {
this.chart.data.datasets[0].data = values
this.chart.update()
})
}
}
<canvas id="my-chart" phx-hook="Chart" data-values={Jason.encode!(@chart_data)}></canvas>
Deploy to Fly.io
fly launch
fly deploy
fly scale count 2
LiveView apps on Fly.io distribute WebSocket connections via clustering with libcluster.