Closed piisalie closed 4 years ago
Thank you! We can't fix those trivially, so we will update the docs. For content_tag, the best is to not use content_tag at all, and write out the HTML. I have heard there are some libraries coming out soon to make it easier to write the HTML out. :)
Thanks for all your hard work on LiveView. The team I am a part of has built a product over the last few months using almost all LiveView with great results. As a testament to it's functionality: we have apparently made many terrible architectural decisions in the process and LiveView continues to work. (in spite of 20kb json blobs being sent often every second)
I understand that
temporary_assigns
can be used to mitigate some of these issues, I'm more interested in gaining insight into what constitutes a good LiveView architecture in a real app and how we can better document that.Environment
Actual behavior
We isolated a few cases where the LiveView diffing behavior was surprising and unexpected. It's not clear to me that it's a bug, but I would love to help improve the docs or functionality in such a way to prevent others from going down this same path.
:one: If an attribute of a Map is updated, every place that Map is used is updated.
I've created a small app recreating this here
If you visit to the
/
route, and then in a separate tab visit/send-message
it will send a message updating themessages
attribute of the Map. The diff sent to the socket looks like this:Any time
messages
is updated, thetitle
attribute is also sent down in the diff even though it didn't change.The template looks like: https://github.com/piisalie/phoenix_liveview_oddities_and_misc/blob/5d5eeab3ae0b38dbf2228fd74a67d990d13e3379/lib/diff_liveview_repo_case_web/live/messages.ex#L7-L14
And the update code: https://github.com/piisalie/phoenix_liveview_oddities_and_misc/blob/5d5eeab3ae0b38dbf2228fd74a67d990d13e3379/lib/diff_liveview_repo_case_web/live/messages.ex#L34-L38
This was problematic for us when rendering multiple lists of items, or nested maps, belonging to the same struct, if one of the attribute lists was updated, all of the places that struct was used was passed down in the diff... which was slightly surprising.
:two: A
content_tag
that relies on socket assigns will send down all of the HTML in the diff (as opposed to just the value that changed).Using the same app as above, if you visit the
/update-thing
route, it will update an assign that is used in a function usingcontent_tag
:https://github.com/piisalie/phoenix_liveview_oddities_and_misc/blob/master/lib/diff_liveview_repo_case_web/live/messages.ex#L7-L14
https://github.com/piisalie/phoenix_liveview_oddities_and_misc/blob/5d5eeab3ae0b38dbf2228fd74a67d990d13e3379/lib/diff_liveview_repo_case_web/live/messages.ex#L44-L50
And updated via: https://github.com/piisalie/phoenix_liveview_oddities_and_misc/blob/5d5eeab3ae0b38dbf2228fd74a67d990d13e3379/lib/diff_liveview_repo_case_web/live/messages.ex#L40-L42
This resulting diff includes all of the HTML:
This sadly can balloon the size of your diffs if you're unaware and using many nested functions / logic, as the whole string gets computed as dynamic and is sent down.
Expected behavior
:one: I would expect for only values of a Map/Struct that changed to get sent in the diff, or for more specific documentation around this behavior to prevent people like me from assigning all of the state to a struct. :upside_down_face:
The problem we were trying to solve with this approach was: how to easily test and manage a complex state. Building a data structure and functions to transform it made sense at the time :joy:.
:two: It would be great if we didn't send down giant strings of html :).... but I think we at least need some more clear documentation here. I understand why technically this is not something that's easily possible, but it wasn't until we started paying attention to diffs and had a large number of items rendered this way that we really realized it was problematic. At that point we were relying on nested
content_tag
functions quite heavily.The problem we were trying to solve with this approach was: easy template sharing and rendering logic across views.
I would love to help with this but at this point I am not sure I fully understand what we want to advocate as "good Live View architecture" in more complicated applications. Hopefully we can expand on that a bit here. :)
Thanks again for everything <3