Добро пожаловать
Исходный кодДобро пожаловать в документацию Phoenix LiveView. Phoenix LiveView позволяет создавать насыщенные пользовательские интерфейсы в реальном времени с помощью HTML, отрисовываемого на сервере. Общий обзор LiveView и его преимуществ доступен в нашем README.
Что такое LiveView?
LiveView — это процессы, которые получают события, обновляют своё состояние и отображают изменения на странице в виде разниц.
Модель программирования LiveView декларативна: вместо того чтобы говорить «когда произойдёт событие X, измените Y на странице», события в LiveView представляют собой обычные сообщения, которые могут вызывать изменения состояния. После изменения состояния LiveView повторно отрисовывает соответствующие части HTML-шаблона и отправляет их в браузер, который обновляет страницу наиболее эффективным способом.
Состояние LiveView — это не что иное, как функциональные неизменяемые структуры данных Elixir. События представляют собой либо внутренние сообщения приложения (обычно отправляемые через Phoenix.PubSub), либо сообщения, отправленные клиентом/браузером.
Каждый LiveView сначала статически отрисовывается в рамках обычного HTTP-запроса, что обеспечивает быстрое время до «первой значимой отрисовки» (First Meaningful Paint), а также помогает поисковым системам и системам индексирования. Затем между клиентом и сервером устанавливается постоянное соединение. Это позволяет приложениям LiveView быстрее реагировать на события пользователя, поскольку по сравнению с запросами без сохранения состояния, для которых при каждом запросе необходимо выполнять аутентификацию, декодирование, загрузку и кодирование данных, требуется меньше работы и передачи данных.
Пример
LiveView включён по умолчанию в приложениях Phoenix. Поэтому для использования LiveView необходимо предварительно установить Phoenix и создать первое приложение. Если вы ещё этого не сделали, ознакомьтесь с руководством по установке Phoenix, чтобы начать работу.
Поведение LiveView задаётся модулем, реализующим набор функций обратного вызова. Рассмотрим пример. Сохраните приведённый ниже файл в lib/my_app_web/live/thermostat_live.ex. Не забудьте заменить каталог my_app_web и модуль MyAppWeb на имя вашего приложения:
defmodule MyAppWeb.ThermostatLive do
use MyAppWeb, :live_view
def render(assigns) do
~H"""
Current temperature: {@temperature}°F
<button phx-click="inc_temperature">+</button>
"""
end
def mount(_params, _session, socket) do
temperature = 70 # Let's assume a fixed temperature for now
{:ok, assign(socket, :temperature, temperature)}
end
def handle_event("inc_temperature", _params, socket) do
{:noreply, update(socket, :temperature, &(&1 + 1))}
end
end
В приведённом выше модуле определены три функции (это обратные вызовы, необходимые для LiveView). Первая из них — render/1, которая получает сокет assigns и отвечает за возврат содержимого, отображаемого на странице. Для определения шаблона HEEx мы используем сигил ~H; это название означает HTML+EEx. HEEx расширяет встроенные шаблоны EEx в Elixir, добавляя проверку HTML, компоненты на основе синтаксиса, интеллектуальное отслеживание изменений и многое другое. Подробнее о синтаксисе шаблонов читайте в разделе Phoenix.Component.sigil_H/2 (обратите внимание: Phoenix.Component импортируется автоматически при использовании Phoenix.LiveView).
Данные для отрисовки поступают из обратного вызова mount. Обратный вызов mount вызывается при запуске LiveView. В нём можно получить доступ к параметрам запроса, прочитать данные, сохранённые в сессии (обычно это данные, позволяющие определить текущего пользователя), и получить сокет. В сокете хранится всё состояние, включая assigns. mount присваивает сокету значение температуры по умолчанию. Поскольку структуры данных Elixir неизменяемы, API LiveView часто получают сокет и возвращают обновлённый сокет. Затем мы возвращаем {:ok, socket}, чтобы сообщить об успешном монтировании LiveView. После mount LiveView отрисует страницу со значениями из assigns и отправит её клиенту.
Если посмотреть на отрисованный HTML, вы заметите кнопку с атрибутом phx-click. При нажатии на кнопку на сервер отправляется событие "inc_temperature", которое сопоставляется с обратным вызовом handle_event и обрабатывается им. Этот обратный вызов обновляет сокет и возвращает {:noreply, socket} с обновлённым сокетом. В LiveView (как и в Elixir в целом) обратные вызовы handle_* вызываются в ответ на определённое действие — в данном случае на нажатие кнопки пользователем. Возвращаемое значение {:noreply, socket} означает, что браузеру не отправляются дополнительные ответы, а лишь отображается новая версия страницы. Затем LiveView вычисляет разницы и отправляет их клиенту.
Теперь мы готовы отобразить LiveView. Можно напрямую предоставить LiveView через маршрутизатор:
defmodule MyAppWeb.Router do
use MyAppWeb, :router
pipeline :browser do
...
end
scope "/", MyAppWeb do
pipe_through :browser
...
live "/thermostat", ThermostatLive
end
end
После отрисовки LiveView отправляется обычный ответ HTML. При создании приложения Phoenix с помощью mix phx.new установщик также создаёт файл ./assets/js/app.js со следующим кодом:
import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view"
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
liveSocket.connect()
Поэтому клиент JavaScript подключится через WebSockets, а mount/3 будет вызван внутри запущенного процесса LiveView.
Параметры и сессия
Обратный вызов mount получает три аргумента: параметры запроса, сессию и сокет.
Параметры можно использовать для чтения данных из URL. Например, если предположить, что где-то определён модуль Thermostat, который может считывать эти данные по названию дома, можно написать следующее:
def mount(%{"house" => house}, _session, socket) do
temperature = Thermostat.get_house_reading(house)
{:ok, assign(socket, :temperature, temperature)}
end
А затем добавить в маршрутизатор:
live "/thermostat/:house", ThermostatLive
Сессия извлекает данные из подписанной (или зашифрованной) cookie. Здесь можно хранить данные для аутентификации, например current_user_id:
def mount(_params, %{"current_user_id" => user_id}, socket) do
temperature = Thermostat.get_user_reading(user_id)
{:ok, assign(socket, :temperature, temperature)}
end
Phoenix включает встроенные генераторы аутентификации. См.
mix phx.gen.auth.
На практике чаще всего используются оба способа:
def mount(%{"house" => house}, %{"current_user_id" => user_id}, socket) do
temperature = Thermostat.get_house_reading(user_id, house)
{:ok, assign(socket, :temperature, temperature)}
end
Иными словами, нужно получить данные о доме, если у пользователя есть к нему доступ.
Привязки
Phoenix поддерживает привязки к элементам DOM для взаимодействия клиента с сервером. Например, чтобы реагировать на нажатие кнопки, нужно отобразить элемент:
<button phx-click="inc_temperature">+</button>
На сервере все привязки LiveView обрабатываются обратным вызовом handle_event/3, например:
def handle_event("inc_temperature", _value, socket) do
{:noreply, update(socket, :temperature, &(&1 + 1))}
end
Для обновления состояния интерфейса, например для открытия и закрытия раскрывающихся списков, переключения вкладок и т. д., LiveView также поддерживает команды JS (Phoenix.LiveView.JS), которые выполняются непосредственно на клиенте, не обращаясь к серверу. Подробнее см. на странице о привязках — полный список всех привязок LiveView — и в руководстве по взаимодействию с JavaScript.
LiveView имеет встроенную поддержку форм, включая загрузку файлов и управление связями. В качестве отправной точки ознакомьтесь с разделом Phoenix.Component.form/1, а для работы со связями — с разделом Phoenix.Component.inputs_for/1. В руководствах «Загрузка файлов» и «Привязки форм» приведены дополнительные сведения о расширенных возможностях.
Навигация
LiveView позволяет переходить между страницами с помощью API pushState браузера. При живой навигации страница обновляется без полной перезагрузки.
Можно либо изменить текущий LiveView, обновив его URL, либо перейти к новому LiveView. Подробнее об этих возможностях читайте в руководстве «Живая навигация».
Генераторы
В Phoenix v1.6 и более поздних версиях есть генераторы кода для LiveView. Чтобы увидеть пример структуры приложения — от базы данных до LiveView, — выполните следующую команду в проекте LiveView:
$ mix phx.gen.live Blog Post posts title:string body:text
Дополнительную информацию можно получить, выполнив mix help phx.gen.live.
Чтобы настроить аутентификацию со встроенной поддержкой LiveView, выполните mix phx.gen.auth Account User users.
Разделение состояния, разметки и событий в LiveView
LiveView поддерживает два механизма расширения: функциональные компоненты, предоставляемые шаблонами HEEx, и компоненты с состоянием, известные как LiveComponents.
Функциональные компоненты для организации разметки и обработки событий
Подобно render(assigns) в LiveView, функциональный компонент — это любая функция, которая получает карту assigns и возвращает шаблон ~H. Например:
def weather_greeting(assigns) do
~H"""
<div title="My div" class={@class}>
<p>Hello {@name}</p>
<MyApp.Weather.city name="Kraków"/>
</div>
"""
end
Подробнее о функциональных компонентах читайте в модуле Phoenix.Component. В конечном счёте они служат полезным механизмом для организации кода и повторного использования разметки в LiveView.
Иногда между LiveView нужно совместно использовать не только разметку. Если вы также хотите вынести обработку событий в отдельный модуль или использовать один и тот же обработчик событий в нескольких местах, функциональные компоненты можно сочетать с Phoenix.LiveView.attach_hook/4.
Live-компоненты для инкапсуляции дополнительного состояния
Иногда компоненту требуется управлять не только собственными событиями, но и отдельным состоянием. Для таких случаев LiveView предоставляет Phoenix.LiveComponent, которые отображаются с помощью live_component/1:
<.live_component module={UserComponent} id={user.id} user={user} />
У LiveComponents есть собственные обратные вызовы mount/1 и handle_event/3, а также собственное состояние с поддержкой отслеживания изменений, как и у LiveView. Они легковесны, поскольку «работают» в том же процессе, что и родительский LiveView, но сложнее самих функциональных компонентов. Поскольку все они работают в одном процессе, ошибки в компонентах приводят к сбою при отрисовке всего представления. Полный обзор приведён в разделе Phoenix.LiveComponent.
Если вы не уверены, что выбрать — функциональные компоненты или live-компоненты, — по умолчанию выбирайте первые. Используйте вторые, только когда требуется дополнительное состояние.
live_render/3 для инкапсуляции состояния (с изоляцией ошибок)
Наконец, если требуется полная изоляция частей LiveView, можно отобразить один LiveView внутри другого, вызвав live_render/3. Этот дочерний LiveView выполняется в отдельном от родительского процессе и имеет собственные обратные вызовы. Сбой дочернего LiveView не повлияет на родительский. При сбое родительского процесса все дочерние процессы завершаются.
При отображении дочернего LiveView требуется параметр :id, чтобы уникально идентифицировать дочерний элемент. Дочерний LiveView отображается и монтируется только один раз, пока его идентификатор остаётся неизменным. Чтобы принудительно смонтировать его заново с новыми данными сессии, необходимо указать новый идентификатор.
Поскольку вложенный LiveView работает в собственном процессе, это отличный инструмент для создания полностью изолированных элементов интерфейса. Однако это несколько затратная абстракция, если нужно лишь разделить разметку или обработку событий (или и то и другое).
Итоги
- используйте
Phoenix.Componentдля организации кода и повторного использования разметки (при необходимости сочетая их сattach_hook/4для повторного использования обработки событий) - используйте
Phoenix.LiveComponentдля совместного использования состояния, разметки и событий между LiveView - используйте вложенные
Phoenix.LiveViewдля разделения состояния, разметки и событий (с изоляцией ошибок)
Руководства
Документация разделена на две категории. Справочник по API содержит сведения обо всех модулях LiveView, в нём вы подробнее узнаете о Phoenix.Component, Phoenix.LiveView и других модулях.
В LiveView также есть множество руководств, которые помогут вам в работе. Они разделены на материалы по серверной и клиентской частям:
Серверная часть
Эти руководства посвящены функциональности серверной части:
- Assigns и шаблоны HEEx
- Развёртывание и восстановление
- Обработка ошибок и исключений
- Gettext для интернационализации
- Макеты LiveView
- Живая навигация
- Вопросы безопасности
- Телеметрия
- Загрузка файлов
Клиентская часть
Эти руководства посвящены привязкам LiveView и интеграции на стороне клиента:
© 2014 Chris McCord
Licensed under the MIT License.
https://phoenix-live-view.hexdocs.pm/welcome.html