# Phoenix LiveView — Elixir & Phoenix

Source: https://www.geekswithgeeks.com/en/elixir-phoenix/r-liveview

> Build interactive, server-rendered UIs with LiveView.

## Rich interactivity without a JavaScript framework

**Phoenix LiveView** lets you build interactive, real-time interfaces in Elixir. A LiveView is a process on the server that holds the page's **state** in **assigns**. On first request it renders HTML (good for SEO and fast first paint), then the browser opens a **WebSocket** and the LiveView becomes stateful: user events (`phx-click`, `phx-submit`, `phx-change`) are sent to the server, handled in **`handle_event/3`**, the assigns change, and LiveView sends only the **minimal diff** of the HTML that changed. Key callbacks are **`mount/3`** (initial state), `handle_params/3` (URL changes), `handle_event/3` (user interaction) and `handle_info/2` (messages, such as PubSub broadcasts). **Function components** and **live components** structure the UI, **streams** efficiently render large collections without holding them in memory, and **JS commands** handle purely client-side effects. Forms integrate with changesets for live validation. LiveView reached version 1.0 in late 2024. Because each connected user has a process, keep assigns small, and use hooks for the occasional custom JavaScript.

## How LiveView works

The server holds state, receives events and pushes minimal HTML diffs over a WebSocket.

![A browser window and a server process circle connected by a two-way arrow, with small event tokens going up and small diff fragments coming down.](assets/figures/elixir-phoenix/section-7-map.svg) — Figure 7.1 — LiveView events and diffs.

## A live stock counter with a form

mount, handle_event and HEEx with phx bindings.

```elixir
defmodule ShopWeb.StockLive do
  use ShopWeb, :live_view
  alias Shop.Inventory

  @impl true
  def mount(%{"sku" => sku}, _session, socket) do
    if connected?(socket), do: Phoenix.PubSub.subscribe(Shop.PubSub, "stock:#{sku}")
    {:ok, assign(socket, sku: sku, stock: Inventory.stock(sku), qty: 1)}
  end

  @impl true
  def handle_event("reserve", %{"qty" => qty}, socket) do
    qty = String.to_integer(qty)

    case Inventory.reserve(socket.assigns.sku, qty) do
      {:ok, remaining} -> {:noreply, socket |> assign(stock: remaining) |> put_flash(:info, "Reserved #{qty}")}
      {:error, :insufficient} -> {:noreply, put_flash(socket, :error, "Not enough stock")}
    end
  end

  @impl true
  def handle_info({:stock_changed, remaining}, socket), do: {:noreply, assign(socket, stock: remaining)}

  @impl true
  def render(assigns) do
    ~H"""
    <section>
      <h1>{@sku}</h1>
      <p>In stock: <strong>{@stock}</strong></p>
      <form phx-submit="reserve">
        <input type="number" name="qty" value={@qty} min="1" />
        <button disabled={@stock == 0}>Reserve</button>
      </form>
    </section>
    """
  end
end
```

## Curly-brace interpolation in HEEx

Recent LiveView versions interpolate values in HEEx bodies with `{@stock}`, while older templates use `<%= @stock %>`. Attributes have always used `value={@qty}`. Match the style of your Phoenix version.

**Quiz:** After the initial render, what does LiveView send to the browser when state changes?

- [x] A minimal diff of the changed parts of the HTML over a WebSocket
- [ ] A full page reload
- [ ] A JSON API response that the client renders
- [ ] Nothing

*Answer:* A minimal diff of the changed parts of the HTML over a WebSocket. LiveView tracks changes and sends compact diffs.
