Hello everyone! I'm learning re-frame, and I'm stuck with a problem I don't understand. I started from a re-frame
lein template and I tried to add a list with items having keys this way: [:li {:key i :whatever 3} (str "Item #" i)]
. But the :key
disappears and is not reproduced in the generated HTML, and React complains that the items are missing a key property. Strangely, whatever="3"
is correctly added as an attribute. Can someone explain to me what I'm doing wrong here? Many thanks for your help!
I think we need a meta-data trick here. brb…
The :key
is not supposed to end up in DOM.
Are you sure i
is not nil
and is unique across all siblings? Are you sure React gives you warnings about these particular :li
?
Here is an example from my code:
[:ul {:style (merge utl/hz-flex-wrap
{:list-style "none"
:padding 0
:margin 0})}
(map (fn [jsort]
(let [{:keys [title]} jsort]
^{:key title} ;;; <----- BINGO!!!!!!!!!!!!!!!!!!!!!!!
[:li [sort-bar-option jsort]]))
utl/job-sorts)]
It can be in the metadata or it can be in the props map - either should work.
In the above example, I would just use into
, maybe with :<>
.
Actually, I just noticed “the `:key` disappears and is not reproduced in the generated HTML”. I would not necessarily expect the React-specific “key” to propagate thru to the HTML.
That was my first statement. :)
Thanks for this feedback! However, React is indeed complaining about a missing key attribute, and I don't know how to provide it (I tried both directly in the map and through a ^{:key i}
metadata...
Here is my code:
(defn main-panel []
(let [name (re-frame/subscribe [::subs/name])]
[:div
[:h1 "Hello from " @name]
[:ul
(for [i (range 4)]
[:li {:key i :whatever 3} (str "List item #" i)])]]))
I don't know why it doesn't work. But you can just replace the :ul
block with
(into [:ul]
(map (fn [i]
[:li {:whatever 3} (str "List item #" i)])
(range 4))
OK, so the key
should not appear as an attribute in the DOM then? It is just used by React internally?
Yep.
Great, thanks for this! I'll check it on my more involved example (with :td
in a table).
into
as per @p-himik's example is a good solution, based on your earlier code this also works for me:
(defn main-panel []
(let [name (re-frame/subscribe [::subs/name])]
[:div
[:h1 "Hello from " @name]
[:ul
(for [i (range 4)]
^{:key (gensym)}
[:li {:whatever 3} (str "List item #" i)])]]))