Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reagent React Clojurescript Warning: Every element in a seq should have a unique :key

I have copied a two year old gist from here. It is now working with Figwheel and uses a more recent version of Reagent/React. I am looking for a generic way of isolating this warning message that comes to the Javascript console: Warning: Every element in a seq should have a unique :key. The idea is to put a :key with a generated unique value into all the components. Then the messages ought to disappear and I'll be in a position to see which components needed the unique :key. My problem is that even although a unique :key is being put into all of them, the warning message is still seen.

So - would someone be able to tell me which component I have missed or otherwise what I've done wrong? As you can see from the source (permalink) I have added :key (gen-key) to the two components: [:polyline {:key (gen-key) ... and [:svg {:key (gen-key) ... at lines 43 and 68 respectively.

Edit So this is the answer (permalink), in terms of code anyway. Just look for the placement of ^{:key (gen-key)} at lines 44 and 60.

Note that the function gen-key was made for debugging. Natural keys to replace.

This is how you might implement gen-key:

(defn gen-key []
  (gensym "key-"))

And here's the way done in the links above:

(def uniqkey (atom 0))
(defn gen-key []
  (let [res (swap! uniqkey inc)]
    (u/log res)
    res))
like image 710
Chris Murphy Avatar asked Oct 31 '15 00:10

Chris Murphy


2 Answers

From the example at the Reagent Project site

(defn lister [items]
  [:ul
   (for [item items]
     ^{:key item} [:li "Item " item])])

(defn lister-user []
  [:div
   "Here is a list:"
   [lister (range 3)]])

Note: The ^{:key item} part above isn’t really necessary in this simple example, but attaching a unique key to every item in a dynamically generated list of components is good practice, and helps React to improve performance for large lists. The key can be given either (as in this example) as meta-data, or as a :key item in the first argument to a component (if it is a map). See React’s documentation for more info.

and the react documentation on dynamic children should point you in the right direction. At a high level, if you have some code which generates a number of similar components in some sort of loop, you need to prefix each component with the ^{:key val}. However, as reagent needs things to be in vectors, you will typically need to wrap the output from the looping construct in some other vector, such as the [:ul] in the above example or a [:div] in a general case. I sometimes use a (into [:div] (for ....)) type of construct to do this.

like image 156
Tim X Avatar answered Dec 17 '22 07:12

Tim X


I believe you need to supply the :key as metadata instead, like e.g.

^{:key (gen-key)} [:polyline ...

I think that it only can be added as a map entry for components, like you do here:

[trending-app {:key (gen-key) :state-ref paths-ratom :comms ch}]

So the above works, but not e.g.

[:svg {:key (gen-key)
like image 27
PeakCode Avatar answered Dec 17 '22 08:12

PeakCode