LiveView开发模式技能Skill liveview-patterns

这个技能专注于Phoenix LiveView框架的模式和最佳实践,用于构建高效、交互式的Web应用。关键词:Phoenix, LiveView, Elixir, Web开发, 异步处理, 内存优化, 实时交互, 服务器端渲染

后端开发 0 次安装 0 次浏览 更新于 3/11/2026

name: liveview-patterns description: Phoenix LiveView 模式与最佳实践。在构建 LiveView 交互功能时加载。 user-invocable: false

LiveView 模式参考

用于构建 Phoenix LiveView 1.0/1.1 的参考。

铁律 — 切勿违反这些

  1. 在断开连接的 mount 中不要进行数据库查询 — 查询会运行两次(HTTP + WebSocket)。使用 assign_async
  2. 始终对列表使用流 — 常规分配 = 每个用户 O(n) 内存。流 = O(1)
  3. 在订阅前检查 connected?/1 — 防止双重订阅
  4. 在 assign_async 闭包前提取变量 — 闭包会复制整个引用的变量
  5. 在 mount/3 中加载主要数据,分页在 handle_params/3 中 — handle_params 在每次 URL 更改时运行
  6. 切勿将 socket 传递给业务逻辑 — 在调用上下文前提取数据
  7. 在 UI 调试前检查变更集错误 — 静默表单保存 = 先检查 {:error, changeset},而不是视口/JS
  8. 所有必需嵌入字段使用隐藏输入 — 嵌入模式中的每个必需字段,如果不可直接编辑,必须有一个 hidden_input
  9. 切勿对生命周期值使用 assign_newassign_new 如果键存在则跳过函数。对语言环境、当前用户或每次 mount 刷新的任何值使用 assign/3

内存影响

模式 3K 项 10K 用户 × 10K 项
常规分配 ~5.1 MB ~10+ GB
~1.1 MB 最小 (O(1))

决策:列表项 >100 → 使用流,而不是分配

快速模式

异步分配(关键)

def mount(%{"slug" => slug}, _session, socket) do
  # 在闭包前提取所需值
  scope = socket.assigns.current_scope

  {:ok,
   socket
   |> assign_async(:org, fn -> {:ok, %{org: fetch_org(scope, slug)}} end)}
end

列表流

def mount(_params, _session, socket) do
  {:ok, stream(socket, :items, Items.list_items())}
end

# 插入/更新/删除
stream_insert(socket, :items, item, at: 0)
stream_delete(socket, :items, item)

带 connected? 检查的 PubSub

def mount(_params, _session, socket) do
  if connected?(socket), do: Chat.subscribe(room_id)
  {:ok, socket}
end

导航决策树

相同 LiveView,不同参数? → patch / push_patch
不同 LiveView,相同 live_session? → navigate / push_navigate
不同 live_session 或非 LiveView? → href / redirect

组件决策树

组件是否需要内部状态和事件处理?
│
├── 是 → 是否封装应用程序逻辑(不仅仅是 DOM)?
│   ├── 是 → 使用 LiveComponent ✅
│   └── 否 → 重构为函数组件,由父组件处理
│
└── 否 → 使用函数组件 ✅

官方指南:“优先使用函数组件而非实时组件”

常见反模式

错误 正确
没有 assign_async 的数据库查询 对所有查询使用 assign_async
对列表使用 assign(socket, items: list) 使用 stream(socket, :items, list)
没有 connected? 的 PubSub 订阅 if connected?(socket), do: subscribe()
将 socket 传递给上下文函数 先提取 socket.assigns
handle_event 中的业务逻辑 委托给上下文
在钩子中对语言环境/用户使用 assign_new 使用 assign/3(必须每次 mount 运行)

参考资料

详细模式,请参见:

  • references/async-streams.md - assign_async、stream_async、流
  • references/forms-uploads.md - 表单、验证、文件上传
  • references/components.md - 函数组件、LiveComponents
  • references/pubsub-navigation.md - PubSub、导航、JS 命令
  • references/js-interop.md - 第三方 JS 库、phx-update=“ignore”、钩子
  • references/channels-presence.md - Phoenix Channels、Presence、令牌认证