lustre-labs / lustre

A Gleam web framework for building HTML templates, single page applications, and real-time server components.
https://hexdocs.pm/lustre
MIT License
1.19k stars 76 forks source link

`element.map` disables keyed update #170

Closed pocka closed 2 months ago

pocka commented 3 months ago

It seems a use of element.map disables keyed element updates. While DOM nodes have data-lustre-key attribute, nodes are being reused.

import gleam/list
import lustre
import lustre/element.{type Element, element}
import lustre/element/html
import lustre/event

// MAIN ------------------------------------------------------------------------

pub fn main() {
  let app = lustre.simple(init, update, view)
  let assert Ok(_) = lustre.start(app, "#app", Nil)
}

// MODEL -----------------------------------------------------------------------

type Model =
  List(String)

fn init(_flags) -> Model {
  ["foo", "bar", "baz"]
}

// UPDATE ----------------------------------------------------------------------
pub opaque type Child {
  Reverse
}

pub opaque type Msg {
  ChildMsg(Child)
}

fn update(model: Model, msg: Msg) -> Model {
  case msg {
    ChildMsg(Reverse) -> list.reverse(model)
  }
}

// VIEW ------------------------------------------------------------------------

fn view(model: Model) -> Element(Msg) {
  html.div([], [
    html.text("parent"),
    html.div([], [
      element.keyed(html.ol([], _), {
        use str <- list.map(model)

        #(
          str,
          html.li([], [
            html.button([event.on_click(Reverse)], [element.text(str)]),
          ]),
        )
      }),
    ])
      |> element.map(ChildMsg),
  ])
}

Without element.map it works as expected.

fn view(model: Model) -> Element(Msg) {
  html.div([], [
    html.text("parent"),
    html.div([], [
      element.keyed(html.ol([], _), {
        use str <- list.map(model)

        #(
          str,
          html.li([], [
            html.button([event.on_click(ChildMsg(Reverse))], [element.text(str)]),
          ]),
        )
      }),
    ]),
  ])
}
hayleigh-dot-dev commented 3 months ago

Thank you for the reproduction! I have a few other vdim-related issues so hopefully I can knock them all out at once 💪

pocka commented 2 months ago

Confirmed a fix on the main branch, thanks!