DaAnalyst

DaAnalyst

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?

Showing Posts 1 to 10

dom

dom

How about keeping A in an assign, but marking it with :temporary_assigns? Do you have a reason to keep it out of assigns besides memory usage?

DaAnalyst

DaAnalyst OP

Temporary assigns are also assigns, it’s just that they get reset to a predetermined value by the framework. The reason why I’d like to, if possible, pass it to the template some way other than via assigns is that I don’t need it assigned and I don’t need the liveview to bother with it as the assigned changes that matter (that trigger the liveview to rerender) are assigned as well so there’s no need for this structure to trigger it as well. Actually, the thing is that I don’t know what the expense of having structures assigned to LV socket with respect to the LV behavior is. The documentation is very opaque on the inner workings of the LV and I simply don’t have time to reverse engineer the code.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

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.

DaAnalyst

DaAnalyst OP

No. I do it in handle_info where I handle data model change messages (that I subscribe my LV module to). But it’s pretty much the same thing,

Correct me if I am wrong, but AFAIK the LiveView simply requires whatever to change in its assigns to rerender. And when re-rendering it’s sending the diffs resulting from your template code.

Thank you for pointing this out. Just needed this confirmation so I don’t waste time speculating. As I said, my structure A instance gets fully reconstructed based on other data (structure B and some other data) that get assigned anyway, so technically, another assign of structure A (which is a data transformation of the aforementioned) is redundant. The only reason why I end up needing it assigned is the point that you emphasized (being the only method to pass it to the template). Just wanted to make that clear. Thanks.

DaAnalyst

DaAnalyst OP

Btw, this is the second time so far I happen to need something like :ignored_assigns.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Live view has several optimizations to do better than this. For example if you render a partial, and none of the assigns passed to the partial have changed, the entire partial will not be re-rerendered. This may be true for things like if blocks too, I don’t remember off the top of my head.

Ah so, this might seem to be the same, but it is importantly very different. Render is called after every handle_ function returns, every time. If the only thing that ever happens is a specific handle_info clause then I guess they’ll run with basically the same frequency, but I do think the distinction matters.

Can you elaborate how this would work?

DaAnalyst

DaAnalyst OP

Look. For all I know, it takes a single non-related assign to get it to rerender everything that changed. For instance, if you have an input text change that you handle the blur event for and your business logic rejects the change for some reason, you can’t just change this specific state in your liveview structure for it remained as it was prior to the change and LV would not revert the content of the input text element to what it was before. That is unless, of course, you assign, say an unrelated temporary assign which will make it take into account the diffs between the dom tree and the liveview state and, effectively, revert the undesired change in the input field.

Of course.

It would simply denote the particular assign as an argument available to the template, that is should any rerendering be triggered otherwise, but should not consider the particular assign to trigger the rerendering.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

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

DaAnalyst OP

Maybe, but you must admit that even you called for it implicitly several comments above:

I don’t do things like this for I don’t keep any logic whatsoever in my templates, but I’d like to know why you are suggesting it be wrong execution-flow -wise if at all. Or it’s about error/exception handling, suggesting the template should only read pre-computed data from structures (which too can be subject to runtime exceptions, so I don’t see the point if this is the argument).

Not my case. I don’t need it for later use, I just don’t know the expense for LV to handle each assign and by default, I tend to minimize the unnecessary operations, although this expense may be insignificant. As originally stated, calling the computation function directly from template would be ideal (unless there is something I am not aware of), for this is a completely redundant state to the one already assigned to the LV socket.

Btw, how do I access this private key if I want anything stored there? Manually - by modifying the structure directly? I am not aware of LV functions for that.

Also, if I store anything in this private key, is it like an assign or like a temporary assign in terms of the lifecycle?

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

It is like an assign, in that once placed is is there in memory, although it is not available in the template, nor will changing it trigger a re-render. Think ordinary genserver state.

Yes, it is a documented part of the structure, you can safely access it directly.

If I was unhappy about assigns being the only way to get data in, then sure, but I’m very happy that assigns are the only way to get data in. This provides all sorts of wonderful guarantees that make reasoning about views easier, and provides great hooks for automatic optimizations that obviate the need to try to create complicated ones like you are doing.

It’s wrong because the moment you have side causes rendering isn’t pure. If rendering isn’t pure, it makes the question “when to render” a vastly more complex one that you suddenly have to manage. LiveView’s paradigm, much like react and other similar paradigms is: Update the state => render. If the state updates, the output from render will reflect that state. This is an amazing guarantee, and it makes reasoning about live view incredibly easy. If you introduce side causes, changing state is no longer enough to know that you need to trigger a re-render. Your ability to reason in a linear path about the state of the live view process and the content of the template goes out the window.

Pure render functions improve performance as well. You seemed to simply not believe me before, but LiveView really does have the assign diffing optimizations, and with pure rendering it can also safely increase those optimizations as time goes on. I know for sure it works with live components and render calls, if you didn’t see it in your use case I’m happy to dig into the specifics with actual code. If render functions aren’t pure though, the ability to get automatic optimizations via assign diff tracking also goes out the window, because we no longer know that we can derive a template from the assigns.

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
AstonJ
Since we have deprecated our Erlang sections (as we have dedicated Erlang Forums now) let’s add this thread for those who’d like to post ...
New
maennchen
:warning: Security advisory: Decimal DoS vulnerability A vulnerability has been published for decimal where very large exponents can cau...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New

Other Trending Topics Top

marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews