I’m facing an issue where the socket
appears to get reset ( no data persisted ) when i try to navigate to parent with LiveComponent.
the mount/1
of component should receive socket from push_patch
but there’s no data in socket whatsoever…
here’s my relevant code:
router
live "/servers/:name/users", ServerShowLive, :server_users
live "/servers/:name/info", ServerShowLive, :server_info
parent handle_event/3
def handle_event("server_users", params, socket) do
server_name = socket.assigns.server.name
socket =
socket
# |> assign(server: socket.assigns.server)
|> push_patch(to: "/servers/#{server_name}/users")
{:noreply, socket}
end
segment of parent with live component embedded
<%= if @live_action == :server_users do %>
<div phx-mounted={JS.set_attribute({"aria-checked", "true"}, to: "#server-users-btn")}>
<%= live_component(DopplerWeb.ServerUsersLive , id: @server.name, server: @server) %>
</div>
<% end %>
mount/1
of component
def mount(socket) do
IO.puts("Socket Component")
IO.inspect(socket)
# more stuff here
I’ve read the documentation several times, ChatGPT’d and losing my sanity over this.
Live components have their own socket
struct which is separate from their parent. push_patch
isn’t sending the socket to the component, it’s merely performing a request to /servers/#{server_name/users
and patching the DOM with the diff. I’ll admit I’m not entirely clear on exactly what you’re doing as you left out the #server-users-btn
. I feel like maybe you’d do better with just a <.link patch={...}>
?
In any event, in order to receive assigns in a live component, you do so in update/2
, which gets called immediately after mount/1
as well as any time the component gets updated:
def update(assigns, socket) do
socket =
socket
|> assign(:id, assigns.id)
|> assign(:server, assigns.server)
# or simply socket = assign(socket, assigns)
{:ok, socket}
end
2 Likes
Quick sanity check, if by “there’s no data”, you’re referring to the :id
and :server
assigns passed in via
live_component(DopplerWeb.ServerUsersLive , id: @server.name, server: @server)
Try using the update/2
callback instead of the mount/1
callback
it’s just a state of a navigation button, a conditional state depending on live_action
.
so, what we do in mount? just an empty callback? cuz i can’t do stuff in mount without some assigns from websocket.
And thanks for the solution, it fixed my problem but a bit confused i am.
It’s a confusing at first, I agree, and it’s an assumption a lot of people make. mount/1
can be used to initialize any assigns with defaults, like in ye olde counter example:
def mount(socket) do
{:ok, assign(socket, :count, 0)}
end
update/2
could also be thought of as handle_assigns
though update
is the better name since it’s called whenever the component is updated.
1 Like