
Escuchar este post
Selecciona una voz y genera audio para escuchar este post
Ya entendemos la teoría detrás de Phoenix LiveView: nos permite crear interfaces interactivas sin tocar JavaScript. Ahora, vamos a ver esa magia en acción con el ejemplo más clásico y claro que existe: un simple contador de clics.
Este ejercicio te demostrará, en menos de 5 minutos, cómo LiveView maneja los eventos del usuario y actualiza la página en tiempo real. ¡Manos a la obra!
Paso 1: Genera tu LiveView
Vamos a pedirle a nuestro amigo, el generador de código, que cree una nueva página LiveView para nosotros. No necesitamos una base de datos esta vez, así que el comando es aún más simple.
En la terminal, dentro de la carpeta de tu proyecto guestbook
, ejecuta:
mix phx.gen.live Counter
Este comando crea dos archivos importantes para nosotros:
lib/guestbook_web/live/counter_live.ex
: Aquí vivirá la lógica de nuestro contador.lib/guestbook_web/templates/counter/index.html.heex
: Esta es la plantilla que verá el usuario.
Paso 2: Conecta la Ruta
Igual que antes, tenemos que decirle a nuestra aplicación en qué URL queremos que viva nuestro contador. Abre el archivo lib/guestbook_web/router.ex
y, dentro del bloque scope "/", GuestbookWeb do
, añade esta línea:
live "/counter", CounterLive.Index, :index
Con esto, le hemos dicho a Phoenix: "Cuando alguien visite /counter
, muéstrale nuestro CounterLive
".
Paso 3: Escribe la Lógica (¡En Elixir!)
Ahora viene lo interesante. Abre el archivo lib/guestbook_web/live/counter_live.ex
. Verás algo de código ya generado. Vamos a modificarlo para que se parezca a esto:
defmodule GuestbookWeb.CounterLive.Index do use GuestbookWeb, :live_view @impl true def mount(_params, _session, socket) do # Asignamos el valor inicial de nuestro contador {:ok, assign(socket, :count, 0)} end @impl true def handle_event("increment", _value, socket) do # Cuando recibimos el evento "increment", actualizamos el contador {:noreply, update(socket, :count, &(&1 + 1))} end @impl true def handle_event("decrement", _value, socket) do # Cuando recibimos el evento "decrement", actualizamos el contador {:noreply, update(socket, :count, &(&1 - 1))} end end
¿Qué hemos hecho aquí?
mount
: Esta función se ejecuta cuando la página carga. Le decimos que el valor inicial decount
es0
.handle_event
: Estas funciones "escuchan" los eventos que vienen de la página. Hemos creado una para"increment"
y otra para"decrement"
. Cada una simplemente actualiza el valor decount
.
Paso 4: Crea la Interfaz
Ahora, vamos a decirle a nuestra plantilla cómo mostrar el contador y cómo enviar esos eventos.
Abre el archivo lib/guestbook_web/templates/counter/index.html.heex
y reemplaza su contenido con esto:
<h1 class="text-2xl font-bold">LiveView Counter</h1> <div class="mt-4 text-4xl"> <%= @count %> </div> <div class="mt-4 space-x-2"> <button phx-click="decrement" class="px-4 py-2 font-bold text-white bg-red-500 rounded hover:bg-red-700"> - </button> <button phx-click="increment" class="px-4 py-2 font-bold text-white bg-green-500 rounded hover:bg-green-700"> + </button> </div>
Las partes clave son:
<%= @count %>
: Esto muestra el valor actual de nuestro contador.phx-click="decrement"
yphx-click="increment"
: ¡Esta es la magia! Le estamos diciendo a LiveView: "Cuando alguien haga clic en este botón, envía el eventodecrement
(oincrement
) al servidor".
Paso 5: ¡Pruébalo!
Asegúrate de que tu servidor esté corriendo (con mix phx.server
). Ahora, abre tu navegador y visita http://localhost:4000/counter.
Verás tu contador. Haz clic en los botones +
y -
. El número se actualiza instantáneamente, sin recargar la página. Y lo has logrado todo escribiendo lógica únicamente en Elixir.
Conclusión
Acabas de construir una aplicación web interactiva. Has visto cómo los eventos (phx-click
) viajan desde el navegador al servidor, cómo la lógica en Elixir (handle_event
) los procesa, y cómo el estado (@count
) se actualiza y se refleja en la interfaz, todo de forma casi instantánea.
Esta es la base de todo en LiveView. A partir de aquí, puedes construir funcionalidades mucho más complejas con la misma simplicidad y elegancia. ¡Felicidades!
Abrazo. Bliss. 🤓

¿React-router v7 o Remix v3?
Checa este otro Post
