Phoenix LiveView cho người mới bắt đầu
Bài đăng này đã không được cập nhật trong 3 năm
Bài hướng dẫn này cần bạn đã cài đặt Elixir và Phoenix trước đó
Nếu bạn chưa biết LiveView là gì, thì thực ra là một wrapper bao gồm websocket cho phép truyền dữ liệu và update lại page. Tôi khuyên bạn nên xem bài nói của Chris McCord ở ElixirConf EU 2019 để hiểu hơn.
Initial Setup
Đầu tiên bạn cần tạo một Phoenix Project
$ mix phx.new random_cat --no-ecto
Trả lời Y
khi được hỏi Fetch and install dependencies?
. Ta đang truyền --no-ecto
vì ở đây ta sẽ không thao tác với database.
Để kiểm tra có đang hoạt động không, khởi chạy server và mở trình duyệt lên và vào địa chỉ http://localhost:4000
. Bạn nên nhìn thấy message 'Welcome to Phoenix!' cùng với vài đường link.
$ cd random_cat
$ mix phx.server
Trang này được điều khiển từ hàm index
nằm trong lib/controllers/page_controller.ex
. Giờ thì ta cần cài đặt thêm LiveView. Để làm vậy, mở file mix.exs
và thêm {:phoenix_live_view, "~> 0.3.1"}
vào deps
, cũng như thêm cả httpoison
. Đây là một thư viện HTTP client, cần thiết cho project này:
defp deps do
[
{:phoenix, "~> 1.4.9"},
{:phoenix_pubsub, "~> 1.1"},
{:phoenix_html, "~> 2.11"},
{:phoenix_live_view, "~> 0.3.1"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:httpoison, "~> 1.6.1"},
{:gettext, "~> 0.11"},
{:jason, "~> 1.0"},
{:plug_cowboy, "~> 2.0"}
]
end
Khởi động lại server và thêm các thư viện bằng lệnh mix deps.get
. Sau đó khởi động lại server bằng mix phx.server
.
LiveView
Đây là phần thú vị. Đầu tiên định nghĩa /live
endpoint. Mở lib/random_cat_web/endpoint.ex
và thêm socket "/live", Phoenix.LiveView.Socket
:
defmodule RandomCatWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :random_cat
socket "/live", Phoenix.LiveView.Socket
...
end
Ta cần thêm signing salt, mở config/config.exs
, thêm live_view: [signing_salt: ...]
config :random_cat, RandomCatWeb.Endpoint,
url: [host: "localhost"],
secret_key_base: "abc",
render_errors: [view: RandomCatWeb.ErrorView, accepts: ~w(html json)],
pubsub: [name: RandomCat.PubSub, adapter: Phoenix.PubSub.PG2],
live_view: [signing_salt: "xyz"]
Bạn có thể sinh salt bằng mix phx.gen.secret 32
.
Tiếp theo bạn cần khởi tạo socket connection qua javascript. Thêm phoenix_live_view
vào npm dependencies:
{
"dependencies": {
"phoenix": "file:../../../deps/phoenix",
"phoenix_html": "file:../../../deps/phoenix_html",
"phoenix_live_view": "file:../../../deps/phoenix_live_view"
}
}
Và chạy npm install --prefix assets
.
Giờ thì mở assets/js/app.js
và thêm:
import {Socket} from "phoenix"
import LiveSocket from "phoenix_live_view"
let liveSocket = new LiveSocket("/live", Socket)
liveSocket.connect()
Đến đây là tất cả Javascript ta cần viết.
Giờ thì ta tạo LiveView. Tạo một file bên trong lib/ranom_cat_web/live
(bạn cần tạo thư mục live
trước), tên là cat_live.ex
, với nội dung:
defmodule RandomCatWeb.CatLive do
use Phoenix.LiveView
def render(assigns) do
~L"""
<img src="<%= @url %>">
"""
end
def mount(%{}, socket) do
fallback = "http://lorempixel.com/g/500/300/animals/"
case HTTPoison.get("http://aws.random.cat/meow") do
{:ok, %HTTPoison.Response{body: body}} ->
case Jason.decode(body) do
{:ok, %{"file" => url}} ->
{:ok, assign(socket, :url, url)}
{:error, _} ->
{:ok, assign(socket, :url, fallback)}
end
{:error, _} ->
{:ok, assign(socket, :url, fallback)}
end
end
end
Giờ thì ta sẽ phân tích từng đoạn. Cơ bản LiveView cần 2 hàm để hoạt động, render
và mount
. Đâu tiên là hàm render
.
def render(assigns) do
~L"""
<img src="<%= @url %>">
"""
end
Đoạn này định nghĩa làm các nào bạn render ra nội dung. Ở đây có thể là toàn bộ trang, hoặc chỉ là một phần. Bạn cũng có thể tạo ra một template. Phần -L
gọi là một sigil cho live view template.
def mount(%{}, socket) do
fallback = "http://lorempixel.com/g/500/300/animals/"
case HTTPoison.get("http://aws.random.cat/meow") do
{:ok, %HTTPoison.Response{body: body}} ->
case Jason.decode(body) do
{:ok, %{"file" => url}} ->
{:ok, assign(socket, :url, url)}
{:error, _} ->
{:ok, assign(socket, :url, fallback)}
end
{:error, _} ->
{:ok, assign(socket, :url, fallback)}
end
end
Tiếp theo là hàm mount
. Mount được dùng đến khi LiveView
được render lần đầu tiên. Ở đây khá đơn giản, hàm này đang lấy data từ http://aws.random.cat/meow
, fallback khi có invalid data, hoặc không fetch được. Nếu fetch data thành công thì ta hiện ảnh mèo.
Cuối cung ta cần thêm LiveView vào router. Mở lib/random_cat_web/router.ex
, và thêm live "/cat", CatLive
vào scope "/"
:
scope "/", RandomCatWeb do
pipe_through :browser
get "/", PageController, :index
live "/cat", CatLive
end
Giờ thì mọi thứ đã ok, khởi động lại server và mở đường dẫn http://localhost:4000/cat. Ảnh mèo sẽ được hiện ra.
Giờ thì các duy nhất để update lại ảnh là refresh lại trang. Giờ thì ta sẽ thay đổi bằng cách thêm một button để update lại ảnh mà không cần refresh lại trang.
LiveView Event Handling
Ở đây event đang được handled khi bạn gọi một hàm từ trang, và đang được thực hiện qua socket, tuy nhiên bạn không cần quan tâm về điều đó cho lắm. Giờ ta cần bind event vào element và LiveView xử lý.
Đầu tiên ta cần update lại template. Ta sẽ thêm một button để trigger hành động trên server, thông qua phx-click
binding. Hàm render của ta sẽ như sau:
def render(assigns) do
~L"""
<div>
<img src="<%= @url %>">
</div>
<button phx-click="moar">moar!</button>
"""
end
Giờ ta cần tạo một function để handle event click. Ở đây ta muốn cập nhật lại ảnh khi button được click. Do đó ta sẽ sửa lại function mount
, để có thể tái sử dụng HTTP call. Hàm mount
sẽ trông như sau:
def mount(_session, socket) do
{:ok, assign(socket, :url, get_cat_url())}
end
Còn hàm get_cat_url
sẽ trả về cho ta url:
defp get_cat_url() do
fallback = "http://lorempixel.com/g/500/300/animals/"
case HTTPoison.get("http://aws.random.cat/meow") do
{:ok, %HTTPoison.Response{body: body}} ->
case Jason.decode(body) do
{:ok, %{"file" => url}} ->
url
{:error, _} ->
fallback
end
{:error, _} ->
fallback
end
end
Cuối cùng, để handle moar
event, ta gán :url
đến url mới từ get_cat_url
bất cứ khi nào hàm này được gọi.
def handle_event("moar", _values, socket) do
{:noreply, assign(socket, :url, get_cat_url())}
end
Cuối cùng file cat_live.ex
sẽ trông như sau:
defmodule RandomCatWeb.CatLive do
use Phoenix.LiveView
def render(assigns) do
~L"""
<div>
<img src="<%= @url %>">
</div>
<button phx-click="moar">moar!</button>
"""
end
def mount(_session, socket) do
{:ok, assign(socket, :url, get_cat_url())}
end
def handle_event("moar", _values, socket) do
{:noreply, assign(socket, :url, get_cat_url())}
end
defp get_cat_url() do
fallback = "http://lorempixel.com/g/500/300/animals/"
case HTTPoison.get("http://aws.random.cat/meow") do
{:ok, %HTTPoison.Response{body: body}} ->
case Jason.decode(body) do
{:ok, %{"file" => url}} ->
url
{:error, _} ->
fallback
end
{:error, _} ->
fallback
end
end
end
Bài viết được dịch từ: https://kriwil.com/development/phoenix-live-view-beginner-guide/
All rights reserved