Skip to content

phx-hook not working on an element mounted by a LiveComponent #3423

Closed
@borisgoro

Description

Environment

  • Elixir version (elixir -v): 1.17.2
  • Phoenix version (mix deps): 1.17.14
  • Phoenix LiveView version (mix deps): 0.18.3, 0.20.17, 1.0.0-rc.6
  • Operating system: macOS Sonoma
  • Browsers you attempted to reproduce this bug on (the more the merrier): Safari, Chrome
  • Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: yes

Code: https://github.com/borisgoro/hooks_test

I created the app with mix phx.new hooks_test and tried upgrading the live view version to 0.20.12, ..., 1.0.0-rc.6 with the same result.

Define two hooks:

const liveSocket = new LiveSocket('/live', Socket, {
    params: { _csrf_token: csrfToken },
    hooks: {
      Hook1: {
        mounted () {
          console.log('Hook1 mounted')
        }
      },
      Hook2: {
        mounted () {
          console.log('Hook2 mounted')
        }
      }
    }
  })

and a LiveComponent with a "panel" for each hook:

defmodule HooksTestWeb.TestLiveComponent do
  use HooksTestWeb, :live_component

  @impl true
  def render(%{panel: 1} = assigns) do
    ~H"""
    <div id="panel1" phx-hook="Hook1" class="mt-2 p-2 border-2">
      <.panel panel="1" target={@myself} />
    </div>
    """
  end

  def render(%{panel: 2} = assigns) do
    ~H"""
    <div id="panel2" phx-hook="Hook2" class="mt-2 p-2 border-2">
      <.panel panel="2" target={@myself} />
    </div>
    """
  end

  def panel(assigns) do
    ~H"""
    <div><%= "Panel #{@panel}" %></div>
    <button class="mt-2 p-1 border-2" phx-click="panel1" phx-target={@target}>Panel 1</button>
    <button class="mt-2 p-1 border-2" phx-click="panel2" phx-target={@target}>Panel 2</button>
    """
  end

  @impl true
  def handle_event("panel1", _, socket) do
    {:noreply, assign(socket, panel: 1)}
  end

  def handle_event("panel2", _, socket) do
    {:noreply, assign(socket, panel: 2)}
  end
end

Hook1.mounted() is called on the initial render, but Hook2.mounted() is not called when the Panel 2 button is clicked.

Identical code (without the phx-target stuff) works fine in a LiveView:

defmodule HooksTestWeb.HomeLive do
  use Phoenix.LiveView, layout: {HooksTestWeb.Layouts, :app}

  @impl true
  def mount(_params, _session, socket) do
    {:ok, assign(socket, panel: 1)}
  end

  # @impl true
  # def render(assigns) do
  #   ~H"""
  #   <.live_component id="test-lc" panel={@panel} module={HooksTestWeb.TestLiveComponent} />
  #   """
  # end

  @impl true
  def render(%{panel: 1} = assigns) do
    ~H"""
    <div id="panel1" phx-hook="Hook1" class="mt-2 p-2 border-2">
      <.panel panel="1" />
    </div>
    """
  end

  def render(%{panel: 2} = assigns) do
    ~H"""
    <div id="panel2" phx-hook="Hook2" class="mt-2 p-2 border-2">
      <.panel panel="2" />
    </div>
    """
  end

  def panel(assigns) do
    ~H"""
    <div><%= "Panel #{@panel}" %></div>
    <button class="mt-2 p-1 border-2" phx-click="panel1">Panel 1</button>
    <button class="mt-2 p-1 border-2" phx-click="panel2">Panel 2</button>
    """
  end

  @impl true
  def handle_event("panel1", _, socket) do
    {:noreply, assign(socket, panel: 1)}
  end

  def handle_event("panel2", _, socket) do
    {:noreply, assign(socket, panel: 2)}
  end
end

Actual behavior

Browser console displays Hook1 mounted on initial render, nothing when buttons are clicked.

Expected behavior

Browser console displays Hook1 mounted and Hook2 mounted when the corresponding button is clicked.

Metadata

Assignees

Labels

Type

No type

Relationships

None yet

Development

No branches or pull requests

Issue actions