Phoenix (Elixir)MiddleTechnical
Что такое Phoenix LiveView и какую проблему он решает?
Phoenix LiveView позволяет строить интерактивный UI без JS: сервер хранит состояние, при событиях отправляет только HTML-diff через WebSocket, а браузер применяет его к DOM. Первый рендер — стандартный HTTP, последующие обновления — через WebSocket.
Phoenix LiveView: концепция и решаемая проблема
Phoenix LiveView — библиотека для построения интерактивных веб-интерфейсов без написания JavaScript. Она позволяет создавать real-time UI, формы с живой валидацией, автодополнение и другие интерактивные элементы, используя только Elixir на сервере.
Проблема, которую решает LiveView
Традиционно есть два подхода к интерактивности:
- Server-side rendering (SSR): простой, но требует полного перезапроса страницы для каждого действия.
- SPA (React/Vue): интерактивен, но требует REST/GraphQL API, клиентского state-менеджмента, бандлинга и значительного объёма JS-кода.
LiveView предлагает третий путь: серверный рендеринг с WebSocket-синхронизацией состояния. Сервер владеет состоянием, а браузер отображает только diff.
Как работает LiveView
- Первый запрос — обычный HTTP, сервер рендерит полную HTML-страницу (хорошо для SEO и TTI).
- Браузер устанавливает WebSocket-соединение через
phx-socket. - При событии (клик, ввод, таймер) LiveView обновляет состояние на сервере и отправляет только изменившиеся части HTML как diff.
- JS-хук на клиенте применяет diff к DOM — пользователь видит мгновенное обновление.
defmodule MyAppWeb.CounterLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, count: 0)}
end
def handle_event("increment", _params, socket) do
{:noreply, update(socket, :count, &(&1 + 1))}
end
def render(assigns) do
~H"""
<div>
<p>Count: {@count}</p>
<button phx-click="increment">+1</button>
</div>
"""
end
end
Подключение к роутеру
scope "/", MyAppWeb do
pipe_through :browser
live "/counter", CounterLive
live "/users", UserLive.Index
live "/users/:id", UserLive.Show
end
Что LiveView умеет из коробки
- Живая валидация форм через
phx-changeбез перезагрузки страницы. - Загрузка файлов с прогресс-баром.
- Оптимистичные обновления UI через JS-команды.
- PubSub-интеграция для real-time обновлений между пользователями.
- Навигация между LiveView-страницами без полного перезапроса.
- Streams для эффективного рендеринга больших списков.
Когда LiveView не подходит
- Оффлайн-функциональность — нужен JS-фреймворк с локальным хранилищем.
- Высоконагруженные клиентские анимации — лучше CSS или небольшой JS.
- Мобильные приложения — только для веба.
Подводные камни
- Каждый LiveView — отдельный процесс в BEAM: 1000 пользователей = 1000 процессов. При неограниченных данных в assigns память растёт.
- Состояние теряется при перезапуске сервера — используйте
mount/3для восстановления из БД или сессии. - Без JavaScript не обойтись для специфических вещей: JS Hooks нужны для интеграции со сторонними библиотеками.
- Дебаггинг сложнее: события идут через WebSocket, не видны в стандартных HTTP-логах.
- Форма с phx-change отправляет запрос при каждом нажатии клавиши — нужен debounce через
phx-debounce. - Временные артефакты на first render: страница рендерится дважды (HTTP + WebSocket reconnect) — это нормально, но может вызвать мигание.
- Не путайте
push_navigateиpush_patch: первый монтирует новый LiveView, второй обновляет текущий.
Common mistakes
- Сводить liveview к названию метода без lifecycle и failure path.
- Игнорировать модель runtime: Phoenix 1.8 работает поверх Plug, Endpoint, Router, Controllers/LiveViews, PubSub и OTP supervision.
- Не отделять validation, authorization, transaction boundary и business logic.
What the interviewer is testing
- Объясняет liveview через конкретную точку lifecycle в Phoenix (Elixir).
- Приводит корректный минимальный пример без вымышленных методов или callbacks.
- Называет edge cases: пустые значения, ошибки, транзакции, безопасность или concurrency.