react-nativeclojurescriptre-frame

ClojureScript: Getting "Error: Key must be integer" when trying to render a FlatList in a re-frame app


I'm trying to create a prototype SPA which consists of a form with two fields (title and description) and a submit button. On submit, the submission title will be added to a list of items that are being displayed (which I've modeled as a React Native FlatList).

For this, I'm using the template created by PEZ for React Native development: https://github.com/PEZ/rn-rf-shadow. This uses React Native, Expo, Reagent, and re-frame.

The problem here is with the FlatList component. Here is how I have structured it:

[:> rn/FlatList {:data (mapv :title (spaces))
                 :renderItem (fn [item]
                    (r/as-element
                       [:> rn/Text {:style {:font-weight :normal
                                            :font-size 15
                                            :color :black}} (str (. item -item))]))}]

spaces is a Reagent reaction. For context's sake, here is the full root definition:

(defn root []
  (let [space-definition (r/atom {})
        spaces @(rf/subscribe [:get-spaces])]
    [:> rn/View {:style {:flex 1
                         :padding-vertical 50
                         :justify-content :space-between
                         :align-items :center
                         :background-color :white}}
     [:> rn/View {:style {:align-items :center}}
      [:> rn/TextInput {:style {:font-size     16
                                :margin-bottom 20
                                :border "1px solid black"
                                :padding 5}
                        :on-change-text #(swap! space-definition assoc :title %)}]
      [:> rn/TextInput {:style {:font-size     16
                                :margin-bottom 20
                                :border "1px solid black"
                                :padding 5
                                :width 500
                                :height 200}
                        :multiline true
                        :on-change-text #(swap! space-definition assoc :description %)}]
      [:> rn/Button {:title "Submit"
                     :on-press #(rf/dispatch [:add-space @space-definition])}]
      [:> rn/FlatList {:data (mapv :title (spaces))
                       :renderItem (fn [item]
                                     (r/as-element
                                      [:> rn/Text {:style {:font-weight :normal
                                                           :font-size 15
                                                           :color :black}} (str item);;(str (. item -item))
                                       ]))}]
      ]
     [:> StatusBar {:style "auto"}]
     ]
    )
  )

The problem I'm getting here is, on page load, I get an error message "Key must be integer". I've deduced that the problem is being caused by the :data value of the FlatList, (mapv :title (spaces)). However, I'm at a loss as to why this is. From what I've found from investigating online, this can occur when a vector is attempting to be accessed by something other than a number, i.e. (myVector someExpNotNumber). But in this case, it makes no sense to me because (mapv :title (spaces)) should evaluate to an empty Vector on page load, and when I substitute an empty Vector directly to test things out, the page loads fine. So, I'm not sure what's going on here. Why is this error happening?


Solution

  • You are calling (spaces) as a function but it is actually a function? If it actually is a vector you just need (mapv :title spaces)?

    shadow-cljs offers Inspect to quickly verify that you are actually working with the data you think you are working with. For example you can do something like

    (defn root []
      (let [space-definition (r/atom {})
            spaces @(rf/subscribe [:get-spaces])]
        (tap> [:spaces spaces])
        ...
        ))
    

    And then in the UI (default under http://localhost:9630/inspect) it'll show up whenever your component is rendered. Verify that it actually is the data you expected.