DaAnalyst
Passing argument to LV template without assigns
The UC: I have two structures, each with its own lifecycle. The structure A is the larger one and is always fully rebuilt for each LV rendering cycle. The structure B is the configuration of the structure A, is small in size and is intended to be updated (not fully rebuilt) in each LV rendering cycle, with full reset on refresh. The structure B is a perfect candidate for the socket.assigns while the structure A is not for I don’t need it assigned.
However, both the rebuild of structure A instance and the updating of structure B instance take place within a single algo run. The problem that arises here is that I cannot call this algorithm from within the template as I don’t think (correct me if I am wrong) that there is a way to assign the updated structure B instance from the template. While if I run the algo from my LV module (in the handle_info function, for example) the only choice I have then is to assign both instances to socket.assigns for I don’t know how else I can make the structure A instance visible to the template.
In short, is there a point in the LiveView framework where I could compute the instances of both structures and assign just one of them, while making the other one also accessible to the template code, but without assigning it to the socket.assigns?
Marked As Solved
benwilson512
Are you constructing it in the def render callback?
Do note that if live view can determine that the assigns have not changed it will not re-render that part of the page, nor will it push updates over the wire.
Some of this feels like premature optimization.
Assigns are the only way to get a value in the template, you do need it to be assigned. I would start with the simple assign based solution, and then measure memory usage and benchmark various aspects of your live view. If you have memory savings you want to achieve, temporary assigns are the solution. If it isn’t clear how to apply those to your situation, that’s the line of questioning that is likely to be most productive.
Also Liked
benwilson512
The absence of code examples has me a little bit lost here. Let’s make this slightly more concrete. You have @foo, and there is some transform(@foo) that produces a bunch of data you actually want to render, but transform/1 is somewhat expensive yes? So you want to make sure that it only actually gets called if @foo changes, and not simply because some other value @bar changes?
Eg:
# index.html.leex
<html>
<body>
<p><%= @bar %></p>
<p><%= transform(@foo) %></p>
</body>
</html>
If @bar changes a lot, but @foo changes very rarely, you don’t want to re-run transform/1 every time @bar changes.
The first thing I’d do is make sure that this problem actually happens, live view is getting new optimizations all the time, I’d put some kind of debug logging inside transform/1 and validate that it is being in fact called every time @bar changes.
If it is, try moving transform(@foo) into a partial (make sure the partial is .leex):
# _foo.html.leex
<p><%= transform(@foo) %></p>
# index.html.leex
<html>
<body>
<p><%= @bar %></p>
<p><%= render(@live_view_module, "_foo.html.leex", foo: @foo) %></p>
</body>
</html>
This allows optimizations around rendering partials to take place. If that still isn’t working then that sounds like a bug, those optimizations have been in for a while. If you have a BUNCH of state you want to manage around @foo a component may help, but this should help.
You can create some |> assign(:baz, transform(assigns.foo)), and then use @baz in the template, which helps avoid having transform/1 called unnecessarily, but at the expense of having to keep the result of transform/1 in memory. If this is an issue we can explore the temporary assigns route, but without a good illustration of the issue it’s hard to talk about specific tactics. It depends a lot on exactly how expensive transform/1 actually is.
benwilson512
To some extent this is just fundamentally at odds with the live view paradigm. What you’re suggesting is basically a side cause, a value that is not treated as an input to the render function, but rather a thing that simply happens to be available. This is fundamentally at odds with how LiveView (and similar UI frameworks) treat rendering, it is a pure relation between a set of inputs and an outputed template. This is, for example, why calling DateTime.utc_now() in your template or in a view helper will not work correctly, and why you should instead do |> assign(:now, DateTime.utc_now()) and use @now.
However! Perhaps the issue here is that you’re operating as if the socket assigns are the only way to maintain state on the socket. Maybe using the private key of the socket will help, so that you can hold on to a value and then only at some later time actually add it to the assigns to be rendered. You could place the value you get from handle_info in the socket private key, and then you can have some other event move the value from private to assigns when you want it to effect the view.
DaAnalyst
Yes, that is precisely what I am doing now. I was just asking if there was a way not to. And transform/1 is expensive enough for not having to invoke it more than once per cycle.
But, now that you’ve mentioned this private key thing, I’m considering changing the design a bit so that the result of transform/1 keeps gettting assigned but its input data does not (but stored as private instead). Need to check of whether that’s gonna be possible. Thanks!
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








