Fork me on GitHub
#re-frame
<
2024-01-08
>
mesota13:01:43

I am having an issue where child component doesn't render data from a subscription in parent component on refresh. Below is a simplified version of my code: (defn parent-component [] (let [data @(rf/subscribe [:my-sub]) on-change (fn [e] (js/alert e))] [child-component data on-change])) (defn child-component [items on-change] (let [transformed-items (map #(assoc {} :value (:code %) :label (:name %)) items)] ;; Rendering logic using transformed-items )) (rf/reg-sub :my-sub (fn [db _] (:items db))) So, the data is shown on initial render, but not when I refresh the page. For now, as a work around, I'm passing subscription key into the child component and subscribing to it inside the child component. I don't like that approach because it assumes the data will always come from a re-frame subscription, thereby making compromising component reusability. Also, please let me know if this work around is sort of an "anti-pattern" besides making the component less reusable. Thanks.

p-himik14:01:45

What does that "Rendering logic using transformed-items" look like? What do you mean by "initial render"? How is it different from a page refresh?

mesota14:01:14

When the shadow-cljs live reloading happens, I can see the data, but not when I refresh the browser. The rendering logic is antD combo bound to the items, but I've noticed that doesn't make much of difference because when I pass in static data, it works just fine. You can even think of it like regular HTML dropdown

p-himik14:01:59

Hard to say anything without the actual code. Maybe child-component is a form-2 or form-3 component that gets fully re-rendered on hot reload but doesn't get re-rendered on plain data change. Maybe you have a hot reload hook that does something weird. Maybe it's a global interceptor problem. Maybe some global def is causing issues. And so on and on.

mesota14:01:57

Here's the child component followed by the usage: (defn selector [items on-change label] (let [transformed-items (map #(into {} (map (fn [[k v]] {(case k :code :value :name :label :id :id :type :type) v}) %)) items)] (fn [] [:div.column ;; align left [:div.field [:div.label.is-normal {:style {:white-space "nowrap"}} [:label.label label]] [:div.field-body [:div.field [:div.control.is-fullwidth [:> Select (assoc {:style {:width "100%" :height 40} :onChange on-change :options transformed-items :optionFilterProp "label"} ;; TODO: Check if there's a generic version :k "v")]]]]]]))) (defn my-selector [] (let [on-change (fn [e] (js/alert e)) data @(rf/subscribe [:sub-key])] [selector data on-change ""] ))

p-himik14:01:54

Turn it from a form-2 component into a form-1 component. With that code, there's 0 reason to keep it as form-2.

p-himik14:01:17

Also, you can just use clojure.set/rename-keys instead of that into + map + case.

mesota14:01:25

It was form-1 initially, same behavior

p-himik14:01:19

Can you try with form-1 again? How does the code that doesn't work with form-1 look like?

mesota14:01:54

(let [transformed-items (map #(into {}
                                      (map (fn [[k v]] {(case k ;; Meh ... no need to transform all keys FIXME
                                                          :code :value :name :label :id :id :type :type) v}) %))
                               items)]
    (fn []
      [:div.column
       [:div.field
        [:div.label.is-normal {:style {:white-space "nowrap"}}
         [:label.label label]]
        [:div.field-body
         [:div.field
          [:div.control.is-fullwidth
           [:> Select
            (assoc
             {:style {:width "100%" :height 40}
              :onChange on-change
              :options transformed-items
              :optionFilterProp "label"} ;; TODO: Check if there's a generic version
             :k "v")]]]]]])))

mesota14:01:30

I'll change the into case stuff ... copilot shenanigans 🙂

p-himik14:01:52

I have no clue what that code is, but it's definitely not a form-1 component. Also, please use code blocks to format multiline code.

mesota14:01:38

My bad. It wasn't supposed to be wrapped inside a function. It works now that I removed the function. I guess that's a form-1. Didn't know about code block. Thanks.

mesota14:01:29

But that makes me wonder why it shouldn't work with form-2 or form-3.