朋友問,LiveView 把所有的東西都傳到後端才反應,這樣一來一回會不會太慢,
我的回答是看情況,
如果我只是要簡單的打開關閉選單,那我把選單的開關狀態傳到伺服器,再反映到畫面上,還滿浪費的,
對於這種情境 LiveView 提供了 Phoenix.LiveView.JS 模組,裡面有客戶端的特別方法可以在 phx-click
上呼叫,當然,如果需要更複雜的 Javascript 功能或是使用其他 Javascript 套件,隨時都可以用 hook 把他勾進來。
但實際上大部分的情況都是需要伺服器來處理的,好吧除非你做 Javascript 單機遊戲,
用 Javascript 框架也常常做什麼都要跟後端確認。
因為 LiveView 每個客戶端的狀態是在伺服器端,有很多東西要呼叫後端非常好處理,不需要新增一個功能就需要前後端各建一個 API 來溝通。
客戶端的狀態是在伺服器端其中一個優勢就是多人互動變得很方便
我們下一篇要使用 Channel 來做多人聊天室,我們先把個人版本做好
這邊我們可以偷懶一下用產生器來產生訊息的 context
mix phx.gen.context Messages Message messages content author
等等 後面那些是誰
Phoenix 的產生器都很貼心的有說明,我們輸入
mix phx.gen.context
他就會顯示出範例
在我們的的指令裡
mix phx.gen.context Messages Message messages content author
第一個 Messages 是 context 名稱
第二個 Message 是 schema 名稱
第三個 messages 是資料庫表格名稱
其他的是裡面的欄位, context:string 如果是 string 可以省略不打
好了之後我們來修改一下 Messages contextlib/blog/messages.ex
用 context 產生器會幫我們做好 CURD 等相關方法
這邊我們要修改一下 list_messages 方法
為了要讓畫面不要太複雜,
我們幫他加上倒著取的順序條件
def list_messages do
Message
|> order_by(desc: :id)
|> Repo.all()
end
記得
mix ecto.migrate
live("/chat_room", ChatRoomLive, :chat_room)
簡單做,這個就跟 CounterLive 一樣放在 live 資料夾就行了lib/blog_web/live/chat_room_live.ex
defmodule BlogWeb.ChatRoomLive do
# 帶入 LiveView 要用的東西
use BlogWeb, :live_view
# alias 剛剛產生的 Context
alias Blog.Messages
# LiveView 從這邊開始
def mount(_params, _session, socket) do
{:ok,
# 我們這次放盡 assigns 的東西有:
assign(socket, %{
# 新訊息用的 changeset
changeset: Messages.change_message(%Messages.Message{}),
# 讀取目前的訊息
messages: Messages.list_messages(),
# 名字我們些寫死
author: "阿強",
# 強迫 LiveView 更新表單用的序號,算是一個 hack,後面補充
message_sid: 0
})}
end
def handle_event("new_message", %{"message" => message_attrs}, socket) do
# 儲存訊息
case Messages.create_message(message_attrs) do
# 成功的話
{:ok, _message} ->
{:noreply,
assign(socket, %{
# 更新畫面上的 messages
messages: Messages.list_messages(),
# 更新表格上面的 sid 讓表格重畫
message_sid: socket.assigns.message_sid + 1
})}
{:error, changeset} ->
{:noreply, assign(socket, %{changeset: changeset})}
end
end
def render(assigns) do
~H"""
<.message_form changeset={@changeset} author={@author} message_sid={@message_sid} />
<.messages messages={@messages} />
"""
end
def messages(assigns) do
~H"""
<div>
<%= for message <- @messages do %>
<div><%= "#{message.author}: #{message.content}" %></div>
<% end %>
</div>
"""
end
def message_form(assigns) do
~H"""
<.form let={form} for={@changeset} phx-submit="new_message" sid={@message_sid}>
<%= text_input(form, :content, autofocus: true) %>
<%= hidden_input(form, :author, value: @author) %>
</.form>
"""
end
end
這裡有點像是之前做文章列表的簡化版,
因為表格只需要新增,也直接在同個 LiveView 上直接做就行了
但要注意的是如果沒有放隨著送出訊息改變的 sid,因為一直在同一頁,所以送出表格後,LiveView 不會更新我們的表格,畢竟 @changeset 沒有改變,會導致輸入欄在訊息送出後不會清空。
這邊有幾個解法,但最簡單暴力的方式就是放一個會變動的值讓他更新。
(在這次我們每送出一次訊息 sid 就 + 1)
這樣就完成我們的孤僻聊天室
目前只能跟自己聊天