Skip to content

Instantly share code, notes, and snippets.

@joshchernoff
Last active May 7, 2020 18:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshchernoff/677a5a7f21f2c201ab9f754f7fe97d98 to your computer and use it in GitHub Desktop.
Save joshchernoff/677a5a7f21f2c201ab9f754f7fe97d98 to your computer and use it in GitHub Desktop.
How do I optimize LiveView while using pagination?
# lib/MyApp/blog.ex
defmodule MyApp.Blog do
import Ecto.Query, warn: false
alias MyApp.Repo
alias __MODULE__.{Post}
def list_posts(params, user) do
Post
|> from(preload: [:tags])
|> Bodyguard.scope(user)
|> Repo.order_by_published_at()
|> Dissolver.paginate(params)
end
def inc_likes(%Post{id: id}) do
{1, [post]} =
from(p in Post, where: p.id == ^id, select: p)
|> Repo.update_all(inc: [likes_count: 1])
post = Repo.preload(post, [:tags])
Phoenix.PubSub.broadcast(
MyApp.PubSub,
"post:like:*",
{:post_liked, post_id: post.id, likes_count: post.likes_count}
)
{:ok, post}
end
end
# lib/my_app_web/live/post_live/index.ex
defmodule MyAppWeb.PostLive.Index do
use MyAppWeb, :live_view
alias MyApp.Blog
alias MyApp.Blog.Post
alias MyApp.Accounts
@impl true
def mount(_params, session, socket) do
IO.inspect([MyAppWeb.PostLive.Index, "mount"])
if connected?(socket),
do: Phoenix.PubSub.subscribe(MyApp.PubSub, "post:like:*")
current_user =
session["user_token"] && Accounts.get_user_by_session_token(session["user_token"])
{:ok, assign(socket, current_user: current_user)}
end
@impl true
def handle_params(params, _url, socket) do
IO.inspect([MyAppWeb.PostLive.Index, "handle_params"])
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(%{assigns: %{current_user: current_user}} = socket, :index, params) do
{posts, dissolver} = Blog.list_posts(params, current_user)
socket
|> assign(page_title: "Listing Posts")
|> assign(dissolver: dissolver)
|> assign(posts: posts)
end
@impl true
def handle_event(
"inc_post_likes",
%{"post-id" => post_id},
%{assigns: %{posts: posts}} = socket
) do
IO.inspect([MyAppWeb.PostLive.Index, "handle_event", "inc_post_likes"])
{:ok, new_post} = Blog.inc_likes(%Post{id: post_id})
posts =
Enum.map(posts, fn
%{id: ^post_id} ->
new_post
p ->
p
end)
{:noreply, assign(socket, posts: posts)}
end
@impl true
def handle_info(
{:post_liked, [post_id: post_id, likes_count: likes_count]},
%{assigns: %{posts: posts}} = socket
) do
IO.inspect([MyAppWeb.PostLive.Index, "handle_info", :post_liked])
posts =
Enum.map(posts, fn
%{id: ^post_id} = post ->
%{post | likes_count: likes_count}
p ->
p
end)
{:noreply, assign(socket, posts: posts)}
end
end
# lib/my_app_web/live/post_live/index.html.leex
<%= paginate @socket, @dissolver, &Routes.post_index_path/3, :index %>
<div>
<%= for post <- @posts do %>
<div id="<%= post.id %>">
<%= post.title %>
<%= post.excerpt %>
<button
class="text-xs text-center btn-blue focus:outline-none"
phx-throttle="500"
phx-click="inc_post_likes"
phx-value-post-id="<%= post.id %>">
<i class="fas fa-heart"></i> <%= post.likes_count %>
</button>
</div>
<% end %>
</div>
# This is message received on [MyAppWeb.PostLive.Index, "handle_info", :post_liked]
[
null,
null,
"lv:phx-FgzRjasV-pJTQ2vB",
"diff",
{"0":
{"2":
{"d":
[
["1", "<a data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar1\"> <img class=\"w-full\" src=\"https://morphicpro.s3-us-west-2.amazonaws.com/snaps/feae1e93-953f-4ecd-a7d6-465b6443bbe9/large.jpg\" alt=\"foobar1\">\n</a>","Apr 2, 2020","<a class=\"hover:text-gray-600\" data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar1\">foobar1</a>","<p>foobar</p>\n","1","71","<a class=\"bg-gray-600 hover:bg-gray-800 text-xs text-white font-bold py-2 px-4 text-gray-100\" data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar1\"> <span class=\"pr-2\">READ MORE</span> <i class=\"fas fa-arrow-circle-right\"></i>\n</a>",""],
["3", "<a data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar2\"> <img class=\"w-full\" src=\"https://morphicpro.s3-us-west-2.amazonaws.com/snaps/feae1e93-953f-4ecd-a7d6-465b6443bbe9/large.jpg\" alt=\"foobar2\">\n</a>","Apr 2, 2011","<a class=\"hover:text-gray-600\" data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar2\">foobar2</a>","<p>foobar</p>\n","3","3","<a class=\"bg-gray-600 hover:bg-gray-800 text-xs text-white font-bold py-2 px-4 text-gray-100\" data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar2\"> <span class=\"pr-2\">READ MORE</span> <i class=\"fas fa-arrow-circle-right\"></i>\n</a>",""],
["4", "<a data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar3\"> <img class=\"w-full\" src=\"https://morphicpro.s3-us-west-2.amazonaws.com/snaps/feae1e93-953f-4ecd-a7d6-465b6443bbe9/large.jpg\" alt=\"foobar3\">\n</a>","Apr 2, 2010","<a class=\"hover:text-gray-600\" data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar3\">foobar3</a>","<p>foobar</p>\n","4","1","<a class=\"bg-gray-600 hover:bg-gray-800 text-xs text-white font-bold py-2 px-4 text-gray-100\" data-phx-link=\"redirect\" data-phx-link-state=\"push\" href=\"/posts/foobar3\"> <span class=\"pr-2\">READ MORE</span> <i class=\"fas fa-arrow-circle-right\"></i>\n</a>",""]
]
}
}
}
]
# lib/my_app_web/router.ex
defmodule MyAppWeb.Router do
...
scope "/", MyAppWeb do
pipe_through :browser
live "/posts", PostLive.Index, :index
live "/posts/:slug", PostLive.Show, :show
end
..
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment