Socket resets when trying to render/mount LiveComponent

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