Fork me on GitHub
#re-frame
<
2019-12-30
>
fenton06:12:54

What am I doing wrong...I can't get my UI element to react to my DB changes?

(ns dhl-oms.sample
  (:require
   [reagent.core :as r]
   [re-frame.core :as rf]))

(defn create-user [cofx evt]
  (let [username (evt 1)
        db (:db cofx)]
    {:db (assoc db :user username)}))

(rf/reg-event-fx :create-user create-user)

(rf/reg-sub :user #(-> % :user))

(defn main-panel []
  (let [user (rf/subscribe [:user])]
    [:div
     [:p "User value: >" (some-> @user :user) "<"]
     [:button
      {:on-click
       #(rf/dispatch [:create-user "Bob"])}
      "Create user!"]]))

(defn mount []
  (r/render
   [main-panel]
   (js/document.getElementById "app")))

(mount)

(comment
  ;; load page
  @(rf/subscribe [:user]) ;; => nil

  ;; click button
  @(rf/subscribe [:user]) ;; => "Bob"

  ;; but no page refresh?
  )

dpsutton06:12:03

You call (evt 1) when event is bound to [create-user “Bob”]

fenton06:12:14

(evt 1) = "Bob", right...that's what i want to store...just the name (evt 0) = :create-user

dpsutton06:12:21

Ah. I forgot vectors we’re inviolable like that sorry

fenton06:12:38

I had to look that up too 🙂

fenton06:12:35

the db is getting updated correctly with the button press, just the [:p "User value: >" (some-> @user :user) "<"] isn't showing the name... like the component isn't getting re-rendered...

fenton06:12:02

darn, i see it now...should be just @user, not (some-> @user :user)

dpsutton06:12:21

You need a function 2 component I think it’s called? Subscribe and then return a function rather than just the hiccup

fenton06:12:55

@dpsutton seems I dont...just need to deref the subscription and form1 should re-render...

dpsutton06:12:07

sorry. was using phone. you reference the username with (some-> user :user) but create it as just (assoc db :user "Bob")

dpsutton06:12:15

remove the some-> and you're fine

dpsutton06:12:01

you subscribe to (:user db) and then call :user again on the string

fenton06:12:03

yeah, saw that, thanks @dpsutton

aisamu17:12:35

Hi! Is it OK to subscribe and deref inside a reg-sub? (Or should I stick with reg-sub-raw ?) The observed behaviour appears to be equivalent, but I'm unsure re: performance/deduplication/caching (or some conceptual mismatch).

(rf/reg-sub-raw
 :sub-a
 (fn [_ _]
   (rr/reaction
    (let [parameter @(rf/subscribe [:parameter])]
      @(rf/subscribe [:final-sub {:parameter parameter}])))))

(rf/reg-sub
 :sub-b
 :<- [:parameter]
 (fn [[parameter]]
   @(rf/subscribe [:final-sub {:parameter parameter}])))

p-himik17:12:46

Judging by the re-frame code, it should be OK.

👌 4
oliy18:12:38

There is another arity to subscribe which will let you pass in a reaction/subscription, see this slightly outdated tutorial https://github.com/day8/re-frame/wiki/Dynamic-Subscriptions Then you could write it as (re-frame/subscribe [:final-sub] [(re-frame/subscribe [:parameter])])

oliy18:12:08

But you should also read the caveats/advice on that wiki page

aisamu19:12:56

Thanks for the tip!

oliy18:12:24

The code you wrote will probably perform fine but you might find the reaction from final-sub is not bubbling the value up, because the other subs are only running when parameter changes

p-himik18:12:08

Why? The other sub would change if its computation function returns another value as well.

oliy18:12:03

Computation functions only run if their input signals change - either the other subs they have a declared dependency on, or the db by default. Because the final-sub dependency is not declared to re-frame I don't think it would know when it has changed, and therefore not run the computation for sub-b

p-himik18:12:42

> Because the final-sub dependency is not declared to re-frame What does it mean?

p-himik18:12:54

Subs are nothing more than cached glorified Reagent reactions. They work in the exact same way because they're made with the reactions.