phoenixframework / phoenix_live_view

Rich, real-time user experiences with server-rendered HTML
https://hex.pm/packages/phoenix_live_view
MIT License
6.18k stars 930 forks source link

send_update/2 triggers updated() for all components, rather than just one #500

Closed jamilabreu closed 4 years ago

jamilabreu commented 4 years ago

Environment

Actual behavior

I have a list of components with the same phx-hook, and I'm seeing that using:

send_update(AppWeb.ExampleComponent, id: "123", example_assigns: "example")

triggers updated() on all components

Expected behavior

I expected updated() to only trigger for the AppWeb.ExampleComponent with an id of 123

jamilabreu commented 4 years ago

Further info: I have a LiveView with three child LiveComponents that are siblings.

Now noticing that lots of updated() hook methods are triggered - even for hooks in the sibling components (none are nested).

jamilabreu commented 4 years ago

Reproduced here: https://github.com/jamilabreu/send_update_bug

josevalim commented 4 years ago

Yes, it will be called multiple times on the client, because we always remount the whole diff on the client. It is a partial update on the server though. I will clarify it in the docs. Thanks for the reproducing app!

josevalim commented 4 years ago

I was wrong. It is actually a bug. :)

ljubisa41 commented 4 years ago

Sorry to maybe spam this thread. I don't know if this bug is related with problem that I have, but on the first site it looks to me like it does. Please see this post: https://elixirforum.com/t/liveview-updated-hook-problem/27607/2

chrismccord commented 4 years ago

On 0.6.0, this behaves as expected, but note that the updated hooks will all be called on the client because the DOM elements are replaced since you did not give the containers an ID in your components. If you give your divs an id, morphdom will patch the containers rather than replacing them, for example:

      <div phx-hook="ComponentThree" id="<%= @id %>">Component Three</div>

On the server, the updated callback is only executed for the desired component regardless. Thanks!