Add keyed list reconciliation to reactive-list
Items with :key attributes are matched by key across renders — existing DOM nodes are reused, stale nodes removed, new nodes inserted in order. Falls back to clear-and-rerender without keys. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -251,7 +251,8 @@
|
||||
(deref (computed (fn () (len (deref items))))) " items"))
|
||||
(ul :class "space-y-1"
|
||||
(map (fn (item)
|
||||
(li :class "flex items-center justify-between bg-white rounded px-3 py-2 text-sm"
|
||||
(li :key (str (get item "id"))
|
||||
:class "flex items-center justify-between bg-white rounded px-3 py-2 text-sm"
|
||||
(span (get item "text"))
|
||||
(button :class "text-stone-400 hover:text-red-500 text-xs"
|
||||
:on-click (fn (e) (remove-item (get item "id")))
|
||||
@@ -315,10 +316,10 @@
|
||||
(p "Two patterns exist: " (strong "declarative") " (" (code "(span (deref sig))") " — auto-reactive via " (code "reactive-text") ") and " (strong "imperative") " (" (code "create-text-node") " + " (code "effect") " — explicit, full control). Use declarative for simple text, imperative for dynamic classes, conditional DOM, or complex updates."))
|
||||
|
||||
(~doc-section :title "5. Reactive List" :id "demo-reactive-list"
|
||||
(p "When " (code "map") " is used with " (code "(deref signal)") " inside an island, it auto-upgrades to a reactive list. Adding or removing items updates only the affected DOM — no full re-render.")
|
||||
(p "When " (code "map") " is used with " (code "(deref signal)") " inside an island, it auto-upgrades to a reactive list. With " (code ":key") " attributes, existing DOM nodes are reused across updates — only additions, removals, and reorderings touch the DOM.")
|
||||
(~demo-reactive-list)
|
||||
(~doc-code :code (highlight "(defisland ~demo-reactive-list ()\n (let ((next-id (signal 1))\n (items (signal (list)))\n (add-item (fn (e)\n (batch (fn ()\n (swap! items (fn (old)\n (append old (dict \"id\" (deref next-id)\n \"text\" (str \"Item \" (deref next-id))))))\n (swap! next-id inc)))))\n (remove-item (fn (id)\n (swap! items (fn (old)\n (filter (fn (item) (not (= (get item \"id\") id))) old))))))\n (div\n (button :on-click add-item \"Add Item\")\n (span (deref (computed (fn () (len (deref items))))) \" items\")\n (ul\n (map (fn (item)\n (li (span (get item \"text\"))\n (button :on-click (fn (e) (remove-item (get item \"id\"))) \"✕\")))\n (deref items))))))" "lisp"))
|
||||
(p "The " (code "map") " form detects " (code "(deref items)") " is a signal and creates an effect that re-renders the list when items change. " (code "batch") " groups the two signal writes (items + next-id) into one update pass."))
|
||||
(~doc-code :code (highlight "(defisland ~demo-reactive-list ()\n (let ((next-id (signal 1))\n (items (signal (list)))\n (add-item (fn (e)\n (batch (fn ()\n (swap! items (fn (old)\n (append old (dict \"id\" (deref next-id)\n \"text\" (str \"Item \" (deref next-id))))))\n (swap! next-id inc)))))\n (remove-item (fn (id)\n (swap! items (fn (old)\n (filter (fn (item) (not (= (get item \"id\") id))) old))))))\n (div\n (button :on-click add-item \"Add Item\")\n (span (deref (computed (fn () (len (deref items))))) \" items\")\n (ul\n (map (fn (item)\n (li :key (str (get item \"id\"))\n (span (get item \"text\"))\n (button :on-click (fn (e) (remove-item (get item \"id\"))) \"✕\")))\n (deref items))))))" "lisp"))
|
||||
(p (code ":key") " identifies each list item. When items change, the reconciler matches old and new keys — reusing existing DOM nodes, inserting new ones, and removing stale ones. Without keys, the list falls back to clear-and-rerender. " (code "batch") " groups the two signal writes into one update pass."))
|
||||
|
||||
(~doc-section :title "6. Input Binding" :id "demo-input-binding"
|
||||
(p "The " (code ":bind") " attribute creates a two-way link between a signal and a form element. Type in the input — the signal updates. Change the signal — the input updates. Works with text inputs, checkboxes, radios, textareas, and selects.")
|
||||
|
||||
Reference in New Issue
Block a user