lustre-labs / lustre

An Elm-inspired framework for building HTML templates, single page applications, and server-rendered components in Gleam!
https://hexdocs.pm/lustre
MIT License
738 stars 52 forks source link

Support for `html.keyed`? #79

Closed ghivert closed 3 months ago

ghivert commented 3 months ago

Hi!

Is there any support planned for html.keyed, like Html.Keyed in elm?

Thanks!

hayleigh-dot-dev commented 3 months ago

Eventually, yes. Imminently, probably not unless some brave soul dives into the vdom code and PRs it themselves. With regard to vdom and perf-related things I've taken the approach of solving problems as they come up for real users: and so far apps have been small enough (mostly) for this to not be an issue.

If you have a specific perf issue I'd be happy to discuss it, but otherwise we'll have to leave things at a hand-wavey "yeah eventually" ^.^

ghivert commented 3 months ago

OK, I was almost sure about the situation, but I wanted to be sure before diving in the code.


I'm developing a toast module (a little bit à la react-toastify) to inject in the frontend directly, and I'm using Lustre to handle the internal state of the module. Actually, everything is great until I started to add CSS animations, because of the stateful nature of HTML.

Let's illustrate what I say:

  1. Add a toast, queue in lustre is [Toast(id: 1, content: bla)]. Conceptually, we would like to have:
    [stack]
    [toast 1 with animation start to display]
    [/stack]

In the DOM:

<div>
  <toast-animated id=1 [underlying-id="first-toast"]>bla</toast-animated>
</div>
  1. Add a toast, queue in lustre is [Toast(id: 2, content: bla), Toast(id: 1, content: bla)] Conceptually, we would like to have:
    [stack]
    [toast 2 with animation start to display] 
    [toast 1 with animation continues to display]
    [/stack]

    In the DOM:

    <div>
    <toast-animated id=2 [underlying-id="first-toast"]>bla</toast-animated>
    <toast-animated id=1 [underlying-id="second-toast"]>bla</toast-animated>
    </div>

Unfortunately, what's happening under the hood is that lustre is correctly updating the DOM, but the first node in the DOM had an animation running. Lustre will just update the content and the attributes, and animation will continue to run, because the [underlying-id] maintained by the browser will not change. That's why I need to have keys for nodes: to make sure lustre will not update existing nodes with new data.

Am I clear in my explanations? 😅


What I could do to solve such things in a first time would be to compute the animation by hand by using requestAnimationFrame and hooking into lustre, with something like request_animation_frame(msg) -> Effect(msg), calling the update function, and doing the computation, but it could be nice to just throw some CSS (with animation) and watch everything works by itself out-of-the-box.

hayleigh-dot-dev commented 3 months ago

Ahhhh yep that makes total sense – seems pretty important! I'll see what I can do but I can't give a time estimation at the moment.

ghivert commented 3 months ago

Thanks a lot for your reactivity and your help! No worry, I can live without animations first, or do things with rAF, but I think it was valuable to bring the subject on the table!