re-frame

https://github.com/Day8/re-frame/blob/master/docs/README.md https://github.com/Day8/re-frame/blob/master/docs/External-Resources.md
jmckitrick 2020-10-21T02:08:38.182300Z

I’ll have to do some experimenting and see if I can come up with concrete cases.

jmckitrick 2020-10-21T02:09:51.182500Z

Maybe your approach of keeping all events and subs with their components eliminates the issue entirely.

jmckitrick 2020-10-21T03:02:52.182700Z

@p-himik So just to be clear, you’ll have a ns with views/components, and all events and subs are in that namespace, unless factored out for common use elsewhere. So that means namespaced keywords are resolved right there, in those namespaces.

p-himik 2020-10-21T06:40:57.183400Z

Indeed.

p-himik 2020-10-21T06:42:02.183600Z

If an event is used somewhere else, I just

(require '[my-proj.calendar :as calendar])

(dispatch [::calendar/set-date "2020-10-21"])
or something like that.

Ramon Rios 2020-10-21T07:52:04.184Z

(defn policy-details
  []
  (fn []
    (let [policy-details (subscribe [::subs/policy-details])]
      [policy-details-view @policy-details])))

(defn policy-details-view
  [policy-details]
  [theme {:color-primary "#e6ac00"}
   [print-pdf] 
   [form {:namespace :policies:*:policy-details:show
          :class-name (:container style)}
    [page-title {:icon [pdf]
                 :label (str (:policy-name policy-details) " | " (:policy-number policy-details))}]
    [:section {:id "policyheader"}
     [:div {:class-name (:itempolicyheader style)}
      [start-date]
      [label nil "  Start Date  "]
      [:b (:start-date policy-details)]]

     [:div {:class-name (:itempolicyheader style)}
      [end-date]
      [label nil "  End Date  "]
      [:b (:end-date policy-details)]]

     [:div {:class-name (:itempolicyheader style)}
      [calendar]
      [label nil "  Next Settlement  "]
      [:b (:next-settlement policy-details)]]]])

p-himik 2020-10-21T08:06:52.184300Z

Nothing incriminating at all, except that you can remove the inner function in policy-details. But it shouldn't change anything.

p-himik 2020-10-21T08:07:10.184500Z

(defn policy-details
  []
  (let [policy-details (subscribe [::subs/policy-details])]
    [policy-details-view @policy-details]))

Ramon Rios 2020-10-21T08:07:22.184800Z

I don't know if the fact of using a custom compiler is responsible for it

p-himik 2020-10-21T08:07:54.185100Z

It shouldn't be. But I cannot really say anything for certain without an MRE.

Ramon Rios 2020-10-21T08:08:56.185300Z

Another example (reg-event-fx :policies:*:policy-selection:requested               (fn [{:keys [db]} [_ & args]]                 (println ":policies:*:policy-selection:requested" args)                 {:db db                  :dispatch-n [[::customers/needed]                               [::agents/needed]]}))

(defn policy-selection
  []
  (dispatch [:policies:*:policy-selection:requested])
  (let [agents (subscribe [::agents/dropdown-options])
        customers (subscribe [::customers/dropdown-options])
        search-policies (fn [param value]
                          (dispatch [:policies-load param value]))
        value-of (fn [key]
                   @(subscribe [::subs/attribute-value :policies:*:policy-selection:list key]))]
    (fn []
      [policy-selection-view {:agents @agents
                              :customers @customers
                              :action search-policies
                              :value value-of}])))

p-himik 2020-10-21T08:12:03.185500Z

Don't use subscribe in some callbacks that aren't called during the render phase, like view-of might be. But again, it shouldn't really affect anything, it's just a matter of potential memory leakage.

Ramon Rios 2020-10-21T08:14:38.185800Z

How would you code that value-of part? My intention is to avoid calling the same subscription with only one different parameter

p-himik 2020-10-21T08:18:39.186Z

It depends. If value-of is called only during the rendering and not in run time when e.g. a user interacts with the component somehow, then your code is fine. If it's for interactions, then you would have to subscribe to all the data that's required for :value but that doesn't depend on key and then create value-of based on that data, so there no longer a call to subscribe in value-of.

Racheal 2020-10-21T08:58:18.190700Z

Hey, I am having an issue with calling a function in a macros. I have this macro in an utils/vents.clj file

(defmacro reg-event [name kw & opt-map-of-kw]
  `(re-frame/reg-event-db
    ~name
    (fn [db# [_ value#]]
       (merge db#
              {~kw value#}
              (get-map-opt-kw db# value# ~@opt-map-of-kw)))))
I have the get-map-opt-kw in an utils/events.cljs file and used the macro in a different event
(ns quagga.components.header.events
  (:require-macros [quagga.utils.events :as utils-events])
  (:require [clojure.string :refer [blank?]]
            [re-frame.core :as re-frame]
            [day8.re-frame.http-fx]
            [ajax.core :as ajax]
            [chimera.string :refer [substring?]]
            [quagga.utils :refer [label-colors get-project-owner]]
            [quagga.utils.specs.project :refer [check-spec-interceptor]]))

(utils-events/reg-event ::successul-user-profile-response :user-profile)
(utils-events/reg-event ::failed-user-profile-response  :failed-user)
(utils-events/reg-event ::failed-projects-response :failed-projects)
(utils-events/reg-event ::failed-organizations-response :failed-organizations)

(defn filter-string [{:keys [db event-val]}]
  (filter #(substring? event-val
                       (:project-name %)
                       :case-sensitive? false)
          (:nav-bar-projects db)))

(utils-events/reg-event ::filter-nav-projects
                        :project-search-string
                        {:nav-bar-filtered-organizations filter-string})
this is the error I get when I do this. Kindly asking for help to debug this

lukas.rychtecky 2020-10-21T09:03:05.191Z

I am not sure, but you may need to move get-map-opt-kw to clj file or at least to cljc .

Racheal 2020-10-21T09:08:57.191200Z

@lukas.rychtecky that still results to the same error

lukas.rychtecky 2020-10-21T09:11:30.191500Z

Where is a definition of get-map-opt-kw? When you expand the macro, what is the result?

Racheal 2020-10-21T09:18:42.191700Z

this is how it looks like

(defn get-map-opt-kw
  [db event-val opt-map-of-kw]
  (reduce (fn [coll [key value]]
            (let [is-fn? (fn? value)]
              (assoc coll key (if is-fn?
                                (value {:db db :event-val event-val})
                                value))))
          {} opt-map-of-kw))

p-himik 2020-10-21T09:18:59.191900Z

It is trying to find a CLJS function quagga.utils.events/get-map-opt-kw. Do you have a CLJS/CLJC file with that namespace and that function?

Racheal 2020-10-21T09:22:40.192100Z

Yes I do

Racheal 2020-10-21T09:23:18.192300Z

I have that function in a cljs file with quagga.utils.events path

Racheal 2020-10-21T09:23:42.192500Z

should i add that namespace to the clj file that contains the macros?

p-himik 2020-10-21T09:24:23.192700Z

No, it should work just as is. But you can try putting [quagga.utils.events] in the :require list in quagga.components.header.events.

Racheal 2020-10-21T09:24:47.192900Z

cool, let me try that

Racheal 2020-10-21T11:49:00.193100Z

thanks all for your suggestions, adding the namespace in the require list worked

Endre Bakken Stovner 2020-10-21T17:36:52.194600Z

Is it okay to do rf/dispatch! in an :on-change in a text field or is that wasteful?

p-himik 2020-10-21T17:39:16.195Z

You probably mean dispatch without the !. It depends. I don't think it's "wasteful" in any sense, but if you derive the value of the text field from a sub that feeds off of that change, you may have some input issues if you type fast enough. https://day8.github.io/re-frame/FAQs/laggy-input/

Endre Bakken Stovner 2020-10-21T17:40:38.195300Z

Thanks. I'll try. I'm just playing around with re-frame, trying to create something like https://rubular.com/

Endre Bakken Stovner 2020-10-21T17:40:46.195600Z

And yes, without the !

Endre Bakken Stovner 2020-10-21T17:42:11.195800Z

It seems like I'll find a solution in re-com if I run into any problems.

Endre Bakken Stovner 2020-10-21T18:28:37.198200Z

I have two different reg-event-dbs: :fields/path and :fields/structure. I want to create a third thing computed from these. I've tried to do so with a subscription:

(rf/reg-event-db
  :fields/structure
  (fn [db [_ structure]]
    (assoc db :structure structure)))

(rf/reg-event-db
  :fields/path
  (fn [db [_ path]]
    (assoc db :path path)))

(rf/reg-sub
 :result
 
 :<- [:fields/path]
 :<- [:fields/structure]

  (fn [[fields structure]]
    (js/console.log (str "Hi from reg-sub: " fields structure))))
The latter subscription never triggers. What am I misunderstanding?

p-himik 2020-10-21T18:29:44.198300Z

The :<- sugar only works for subscriptions without parameters.

p-himik 2020-10-21T18:30:11.198500Z

Since you have to pass structure and path to the dependencies, you will have to use the desugared version of the signal subs.

p-himik 2020-10-21T18:30:23.198700Z

Consult the docstring of reg-sub for more details.

Endre Bakken Stovner 2020-10-21T18:32:54.199500Z

But this example has parametrized subs, no? https://github.com/day8/re-frame/blob/master/docs/subscriptions.md#syntactic-sugar

p-himik 2020-10-21T18:33:21.199700Z

There are three code blocks on that page. To which one do you refer as the example?

Endre Bakken Stovner 2020-10-21T18:33:46.199900Z

The very last. I tried to link to the exact paragraph

p-himik 2020-10-21T18:34:13.200100Z

I should correct myself - the :<- sugar can accept subs with parameters, but those parameters have to be static, just like 2 in [:b 2].

p-himik 2020-10-21T18:34:51.200300Z

Right, the "Syntactic Sugar" section shows you the sugared version. The :a and :b subs don't accept any parameters from the sub that uses them.

p-himik 2020-10-21T18:35:16.200500Z

You will have to use the Layer 3 sub variant from the second code block.

p-himik 2020-10-21T18:35:57.200700Z

Oh wait, hold on. I have totally misread your original code!

p-himik 2020-10-21T18:36:15.200900Z

You're trying to make a sub depend on events. That has never worked, at least not that way.

p-himik 2020-10-21T18:36:25.201200Z

Subs can receive values from another subs and from app-db, that's it.

p-himik 2020-10-21T18:36:39.201400Z

If you want a sub to change its value in response to some event, that event will have to change app-db.

Endre Bakken Stovner 2020-10-21T18:36:59.201600Z

But I have two reg-event-dbs: those change the app-db, right?

Endre Bakken Stovner 2020-10-21T18:37:10.201800Z

Sorry, I am a confused n00b

p-himik 2020-10-21T18:38:21.202Z

In the examples at the link above, both :a and :b are subs, not events. Yes, those do change app-db. You will have to create subs that extract :structure and :path and use those subs as signals to the :result sub. But if your :result sub doesn't do any heavy computations, you can just avoid the signal subs altogether and just get the values from app-db directly.

Endre Bakken Stovner 2020-10-21T18:39:05.202200Z

Okay. Thanks for your help, I truly appreciate it :thumbsup:

p-himik 2020-10-21T18:39:46.202400Z

And the signature of the :result sub function has to be [[fields structure] _], not [[fields structure]]. Sub functions always accept two arguments, even if the sub itself is never used with any parameters.

p-himik 2020-10-21T18:39:49.202600Z

NP

Endre Bakken Stovner 2020-10-21T18:55:16.206500Z

I have the following code with a subscription that depends on two subscriptions. The console.log never triggers even though I change the :`fields/path` and :fields/structure

(rf/reg-event-db
  :fields/path
  (fn [db [_ path]]
    (assoc db :path path)))

(rf/reg-event-db
  :fields/structure
  (fn [db [_ structure]]
    (assoc db :structure structure)))

(rf/reg-event-db
  :fields/path
  (fn [db [_ path]]
    (assoc db :path path)))

(rf/reg-sub
 :fields/path
 (fn [db _]
 ;  (js/console.log (str "Hello from sub: " (:path db)))
   (:path db)))

(rf/reg-sub
 :fields/structure
 ;(js/console.log (str "Hello from sub: " (:structure db)))
 (fn [db _]
   (:structure db)))

(rf/reg-sub
 :result
 (fn [query-v]
   (js/console.log "Are we ever here?")
   [(rf/subscribe [:fields/path] (rf/subscribe [:fields/structure]))])
 (fn [[fields structure] query-v]
   (js/console.log (str "Hi from reg-sub: " fields structure))
   "mock derived output"))
Can anyone see what is wrong?

p-himik 2020-10-21T18:58:33.206700Z

The error is in this line:

[(rf/subscribe [:fields/path] (rf/subscribe [:fields/structure]))]
Do you see it?

Endre Bakken Stovner 2020-10-21T18:59:06.206900Z

Now I am embarrassed XD

p-himik 2020-10-21T18:59:18.207100Z

Happens. :)

p-himik 2020-10-21T18:59:48.207300Z

Placing signal subs on their own line would help. Also, you can turn that vector into a map and destructure it accordingly.

Endre Bakken Stovner 2020-10-21T19:01:22.207500Z

I think a syntax checker ("wrong number of args") would have caught it. I should set one up.

Endre Bakken Stovner 2020-10-21T19:03:10.207700Z

I fixed that mistake, but still I get no console.log output...

p-himik 2020-10-21T19:03:45.207900Z

Are you actually using :result in some view that gets mounted?

Endre Bakken Stovner 2020-10-21T19:04:16.208100Z

Nope. Are subscriptions lazy? I'll try doing that.

p-himik 2020-10-21T19:04:36.208300Z

Yes, subs are not evaluated if not used.

p-himik 2020-10-21T19:04:58.208500Z

Not the same as lazy per se - more like defining a function and never using it.

Endre Bakken Stovner 2020-10-21T19:06:35.208700Z

Yes, I used the wrong term

Endre Bakken Stovner 2020-10-21T19:07:34.208900Z

How do I use that subscription in hiccup? (rf/<???> :result)

p-himik 2020-10-21T19:08:57.209100Z

It seems like you really should go through the incredibly well-written re-frame documentation and FAQ. It will answer 99% of your questions and in a better fashion than I will, trust me.

Endre Bakken Stovner 2020-10-21T19:10:07.209400Z

I wasn't asking you specifically. Anyways, I found it out

Endre Bakken Stovner 2020-10-21T19:10:19.209600Z

[:div [:p @(rf/subscribe [:result])]]

Endre Bakken Stovner 2020-10-21T19:12:03.209800Z

I am sure the docs are great, but I was too tired to read. I just wanted to play around with code. Now it all works - thanks again. I'll read the docs tomorrow when I am refreshed.

jmckitrick 2020-10-21T20:51:24.210Z

And you generally group the view, event, and subscription all in the same namespace and file?

jmckitrick 2020-10-21T20:52:09.210200Z

What about cases where, say, an http fx is used in different places? I guess a ‘common’ namespace or is there a better way? @p-himik

p-himik 2020-10-21T20:55:09.210500Z

Yep. And yes, just a common ns. Sometimes people extract fxs in a separate special fx ns, I tend to do the same for well-focused tiny effects and I create specialized namespaces for effects that serve the same purpose.

p-himik 2020-10-21T20:56:38.210700Z

IMO it's comparable to just writing functions in Clojure, which is (again, IMO) not that different from writing code in any modern and actively used language. Well, Clojure does have some polymorphism which may create some differences, but re-frame related stuff is not polymorphic so it's more similar to other languages.

p-himik 2020-10-21T21:02:50.210900Z

I have quite a lot of legacy code that does split functionality into views/subs/events, and I'm gradually refactoring it into single namespaces. Working with them, in my experience, proves to be much easier. And simpler, I think. :)

jmckitrick 2020-10-21T21:45:34.211100Z

Ok, that’s the route I’ll try… for some reason I like the idea of separate folders (views, pages, components, etc) because it seems better organized for navigation and reuse, but things are not always as they seem….