Avoiding reloading streams in `handle_params` when live navigating

The built in generators produce a form live component that will notify the parent to reload its data and then live navigate to the index:

  defp save_user(socket, :edit, user_params) do
    case Account.update_user(socket.assigns.user, user_params) do
      {:ok, user} ->
        notify_parent({:saved, user})

        {:noreply,
         socket
         |> put_flash(:info, "User updated successfully")
         |> push_patch(to: socket.assigns.patch)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign_form(socket, changeset)}
    end
  end

With the default live view implementation also produced by the generators, this will result in the handle_params doing very little work and the stream being updated by the handle_info callback. I like this as it produces no extra DB queries since the resulting struct is directly merged into the stream:

  @impl true
  def mount(_params, _session, socket) do
    {:ok, stream(socket, :users, Account.list_users())}
  end

  @impl true
  def handle_params(params, _url, socket) do
    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end

  defp apply_action(socket, :index, _params) do
    socket
    |> assign(:page_title, "Listing Users")
    |> assign(:user, nil)
  end

  @impl true
  def handle_info({TestingWeb.UserLive.FormComponent, {:saved, user}}, socket) do
    {:noreply, stream_insert(socket, :users, user)}
  end

However, for my own live views, I often have filtering applied to the stream based on URL params meaning that I must perform the streaming in the handle_params callback, not mount. So if I were to use a similar approach, the stream would end up being reset needlessly by handle_params despite the fact that it’s not necessary since the params haven’t actually changed.

Wondering if others have encountered this problem and how they would approach it. Thanks!

In these cases, I keep track of the params, compare them with the current params and only update things that need updating.

if params_that_affect_this_assign_changed? do
  socket 
  |> ...
else
  socket
end
1 Like

Yeah this is what I’m settling on, but was wondering if there was anything more clever out there. Thank you!