terenceponce
How to use Phoenix 1.7 Streams on LiveComponent preload?
The recent Phoenix 1.7 came with Streams. The example given in the blog post was straightforward and easy to understand.
However, how would you use them when preloading a LiveComponent?
Given the example about preloading from the docs:
def preload(list_of_assigns) do
list_of_ids = Enum.map(list_of_assigns, & &1.id)
users =
from(u in User, where: u.id in ^list_of_ids, select: {u.id, u})
|> Repo.all()
|> Map.new()
Enum.map(list_of_assigns, fn assigns ->
Map.put(assigns, :user, users[assigns.id])
end)
end
Would it be possible to do it in the Map.put() section? Is it even possible to do streams when preloading?
Marked As Solved
codeanpeace
This preloading example from the docs demonstrates how to avoid an n+1 query, which the stream example from the blog posts accomplishes by calling Blog.list_posts() that likely looks something like def list_posts(), do: Repo.all(MyApp.Post).
So in this case, preloading database resources into socket assigns may well be unnecessary/superfluous since these resources have already been added into the socket streams. And since one of the big advantages of streams is to offload storing of collections in memory on the server, I would think twice about about preloading and storing these same collections in memory on the server via socket assigns when using streams.
I haven’t tested it, but this could be one way of passing streams into multiple LiveComponents via assigns.
defmodule DemoWeb.PostLive.Index do
use DemoWeb, :live_view
alias Demo.Blog
alias Demo.Blog.Post
@impl true
def mount(_params, _session, socket) do
{:ok, stream(socket, :posts, Blog.list_posts())}
end
...
end
# index.html.heex
<%= for post <- @streams.posts do %>
<.live_component module={PostComponent} id={post.id} post={post} />
<% end %>
On another note, the following section of the Phoenix.LiveComponent docs on Preloading and update might help in understanding what @josevalim is saying.
So on first render, the following callbacks will be invoked:
preload(list_of_assigns) -> mount(socket) -> update(assigns, socket) -> render(assigns)On subsequent renders, these callbacks will be invoked:
preload(list_of_assigns) -> update(assigns, socket) -> render(assigns)
Since you need the socket to pass into the stream, stream_insert, or stream_delete functions, only the mount and update LiveComponent callbacks can interact with streams.
Also Liked
josevalim
The main point is that preload does not know about streams. All the data in preload is copied to the socket in the update/2 callback. So that would be the place to insert data into the stream. If you give it a try, I can gladly review and provide pointers.
josevalim
The preload happens outside of the LiveComponent. You don’t really have access to the socket there. So for streams in live components, you can define it on mount, prepare the assigns on preload, and then load them into the stream on update.
josevalim
I just gave some pointers, @codeanpeace gave the proper and complete answer. ![]()
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









