Gesprye 2020-09-30T20:30:51.026500Z

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!

kennytilton 2020-09-30T20:34:46.027Z

I think we need a meta-data trick here. brb…

p-himik 2020-09-30T20:37:00.027100Z

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?

kennytilton 2020-09-30T20:37:05.027300Z

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]]))

p-himik 2020-09-30T20:37:31.027500Z

It can be in the metadata or it can be in the props map - either should work.

p-himik 2020-09-30T20:38:44.027700Z

In the above example, I would just use into, maybe with :<>.

kennytilton 2020-09-30T20:43:13.028100Z

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.

p-himik 2020-09-30T20:44:39.028300Z

That was my first statement. :)

Gesprye 2020-09-30T20:52:50.028600Z

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...

Gesprye 2020-09-30T20:52:58.028800Z

Here is my code:

Gesprye 2020-09-30T20:53:24.029Z

(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)])]]))

p-himik 2020-09-30T20:56:31.029200Z

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))

Gesprye 2020-09-30T21:02:30.029400Z

OK, so the key should not appear as an attribute in the DOM then? It is just used by React internally?

p-himik 2020-09-30T21:05:43.029600Z


Gesprye 2020-09-30T21:06:48.029800Z

Great, thanks for this! I'll check it on my more involved example (with :td in a table).

superstructor 2020-09-30T22:53:59.030200Z

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])]
     [:h1 "Hello from " @name]
      (for [i (range 4)]
        ^{:key (gensym)}
        [:li {:whatever 3} (str "List item #" i)])]]))