I’ll have to do some experimenting and see if I can come up with concrete cases.
Maybe your approach of keeping all events and subs with their components eliminates the issue entirely.
@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.
Indeed.
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.(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)]]]])
Nothing incriminating at all, except that you can remove the inner function in policy-details
. But it shouldn't change anything.
(defn policy-details
[]
(let [policy-details (subscribe [::subs/policy-details])]
[policy-details-view @policy-details]))
I don't know if the fact of using a custom compiler is responsible for it
It shouldn't be. But I cannot really say anything for certain without an MRE.
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}])))
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.
How would you code that value-of part? My intention is to avoid calling the same subscription with only one different parameter
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
.
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 thisI am not sure, but you may need to move get-map-opt-kw
to clj
file or at least to cljc
.
@lukas.rychtecky that still results to the same error
Where is a definition of get-map-opt-kw
? When you expand the macro, what is the result?
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))
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?
Yes I do
I have that function in a cljs file with quagga.utils.events
path
should i add that namespace to the clj file that contains the macros?
No, it should work just as is.
But you can try putting [quagga.utils.events]
in the :require
list in quagga.components.header.events
.
cool, let me try that
thanks all for your suggestions, adding the namespace in the require list worked
Is it okay to do rf/dispatch!
in an :on-change
in a text field or is that wasteful?
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/
Thanks. I'll try. I'm just playing around with re-frame, trying to create something like https://rubular.com/
And yes, without the !
It seems like I'll find a solution in re-com if I run into any problems.
I have two different reg-event-db
s: :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?The :<-
sugar only works for subscriptions without parameters.
Since you have to pass structure
and path
to the dependencies, you will have to use the desugared version of the signal subs.
Consult the docstring of reg-sub
for more details.
But this example has parametrized subs, no? https://github.com/day8/re-frame/blob/master/docs/subscriptions.md#syntactic-sugar
There are three code blocks on that page. To which one do you refer as the example?
The very last. I tried to link to the exact paragraph
I should correct myself - the :<-
sugar can accept subs with parameters, but those parameters have to be static, just like 2
in [:b 2]
.
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.
You will have to use the Layer 3
sub variant from the second code block.
Oh wait, hold on. I have totally misread your original code!
You're trying to make a sub depend on events. That has never worked, at least not that way.
Subs can receive values from another subs and from app-db, that's it.
If you want a sub to change its value in response to some event, that event will have to change app-db.
But I have two reg-event-dbs: those change the app-db, right?
Sorry, I am a confused n00b
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.
Okay. Thanks for your help, I truly appreciate it :thumbsup:
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.
NP
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?The error is in this line:
[(rf/subscribe [:fields/path] (rf/subscribe [:fields/structure]))]
Do you see it?Now I am embarrassed XD
Happens. :)
Placing signal subs on their own line would help. Also, you can turn that vector into a map and destructure it accordingly.
I think a syntax checker ("wrong number of args") would have caught it. I should set one up.
I fixed that mistake, but still I get no console.log output...
Are you actually using :result
in some view that gets mounted?
Nope. Are subscriptions lazy? I'll try doing that.
Yes, subs are not evaluated if not used.
Not the same as lazy per se - more like defining a function and never using it.
Yes, I used the wrong term
How do I use that subscription in hiccup? (rf/<???> :result)
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.
I wasn't asking you specifically. Anyways, I found it out
[:div [:p @(rf/subscribe [:result])]]
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.
And you generally group the view, event, and subscription all in the same namespace and file?
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
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.
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.
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. :)
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….