This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-09-29
Channels
- # beginners (42)
- # boot (12)
- # cider (3)
- # cljs-dev (277)
- # cljsrn (44)
- # clojure (127)
- # clojure-austin (9)
- # clojure-austria (1)
- # clojure-brasil (14)
- # clojure-canada (1)
- # clojure-dev (22)
- # clojure-dusseldorf (1)
- # clojure-italy (4)
- # clojure-russia (24)
- # clojure-spec (33)
- # clojure-taiwan (1)
- # clojure-uk (21)
- # clojure-ukraine (8)
- # clojurescript (134)
- # core-async (41)
- # core-logic (8)
- # cursive (1)
- # datomic (3)
- # ethereum (1)
- # events (4)
- # funcool (1)
- # leiningen (12)
- # off-topic (21)
- # om (19)
- # onyx (45)
- # overtone (1)
- # parinfer (2)
- # pedestal (3)
- # proton (2)
- # re-frame (103)
- # reagent (48)
- # test-check (27)
- # untangled (51)
- # vim (3)
(reg-event-db
:select-country
(fn [db [_ country-id]]
(update-in db [:selections :selected-country] country-id)))
(potentially worth noting? that I’m not using any interceptors and am sticking with the old pattern of every handler having access to the entire db, no contexts)
I don’t see an issue with that code, are you sure the exception is from that handler @samueldev ?
@samueldev do you mean to use assoc-in
?
ah good point @danielcompton, didn’t spot that either! 😉
I’ve written that bug more than once 🙂
thank you @danielcompton
I’m interested to know since you’ve mentioned you have a significant re-frame app @danielcompton, how do you deal with db schema / state for shared components ? e.g. say for example you have a password component that is used in more than one form that has some of its own subs and handlers, does it write to its own db space, or do you pass in a base db key sequence for the shared component to conj onto the key sequence for all its db operations ?
don’t quite understand, can you reframe that question?
@danielcompton at the moment we have stuff like:
(defn emails
[{:keys [title db-base-ks]}]
(let-subs [pending-emails [:email-list/pending-emails db-base-ks]
…
where emails is a shared component for a list of emails between different types of forms, and db-base-ks
is passed into subs/handlers to be used like:
(reg-sub
:email-list/pending-emails
(fn [db [_ db-base-ks]]
(get-in db (conj db-base-ks :pending-emails))))
I hope that’s the first time you’ve used that @danielcompton
ah, I think I see what you mean, do we parameterise functions with a key sequence?
We would probably put that shared thing under it’s own key
but our apps are quite panel like, where each panel mainly operates on it’s own data and there isn’t a lot of sharing, so that may not work for you
Yeah we have shared things of which there could be multiple instances on the same panel/form so it must have a way to seperate the state between the usages of the common component, make sense ?
Not sure if passing in a keq sequence as a db base location is the right solution yet, but it is what we are doing at the moment anyway.
Do you have any shared functions between different subs or handlers ? @danielcompton
oh, I think I see what you’re saying. You’re looking to create common view components which source their data from different places in app-db?
yes :thumbsup:
that is the first question, the second question is just about if you have any functions shared between subs/handlers ?
probably? sorry, I’m feeling a bit dense today, don’t think I’m totally getting your main point
@superstructor I have re-used components and I am using the "pass in a base db key sequence" approach
I've also almost completely eschewed use of subscriptions in favor of localized reagent/atom
or reagent/cursor
(although I can see that it would be nice to have a more frequently utilized global event stream I could tap into for debugging purposes).
When components are cordoned off this way, however, debugging is also localized to individual components.
So, if I were going to answer your second question it would be "no" because I have very few subs/handlers to begin with.
thanks thats very interesting @johanatan, we probably don’t want to introduce localized reagent/atom
or reagent/cursor
as we’d lose some of the benefits of re-frame sub/handler model.
all good @danielcompton, in other words do you have a utils.cljs
or helpers.cljs
for shared operations on db state between subs and handlers ?
@superstructor yes, but in my view the sub/handler model should be reserved for very high level concepts that the entire app cares about; not such things as whether a txt field has this string or that string or whether a radio button is checked or not.
and you can still send those "globalized concerns" as summary events when a transition is taking place from one section to the next
what benefits/disadvantages have you found with that approach ? @johanatan
i do have some handlers which are paragraph-ish in size and for that it definitely makes sense
thanks interesting, so by localized you mean that the reagent/atom
or reagent/cursor
is somewhere in your view form 2 or form 3 components right ? @johanatan
i would imagine another advantage is if you were going to sniff out the global event stream, you wouldn't be bogged down with mundane details but rather would see only high-level/important/summary level events in your debug stream
[but that can cut both ways obviously-- would be nice to have everything in the stream (a la Kafka) and merely filter as needed]
@superstructor: Alternatively, I've found that I have never needed or wanted either r/atom or r/cursor - it's very much possible and recommended by the re-frame "philosophy" to keep all your app-state in app-db. I have absolutely used regular atoms as part of reagent components, similar to how it is done in re-com, and that works well for the apps I've worked on. Experiment and see what works best for you!
do you test that localised state @johanatan ? It strikes me that the testing storey would be a lot harder than in re-frame subs/handlers ?
I agree in principal, we just have some challenges to solve in practice that we havn’t worked out yet. At the moment, we almost religiously keep all state in app-db and do all state changes (not just app-db) via reg-event-db, reg-event-fx, reg-cofx, reg-fx etc. Of course with this we’re now having the problem of how to manage shared things based on app db (like common subs/handlers) and how to share locations within the app db between subs/handlers etc. @shaun-mahood
Trying to figure out how best to structure my app… in the simplest possible explanation; it’s a ostensibly a hierarchical database view… easiest way to explain it is to think of it like a parent -> child -> baby
setup where I have a :location
section in my app-db to determine where someone is currently navigated to in the hierarchy
if someone is viewing a child
and they navigate to a parent
that is not the parent of their currently selected child
(saved in :location
in app-db), I need to clear their child
selection & transitively every other selection they might have down the hierarchy
I can think of a way to do that off the top of my head via interceptors and dispatching a wipe-everything-below-this-in-the-selection-hierarchy
event, upon receiving a “they chose a new parent” event
@superstructor: good question. In any app I think there is a thin veneer of functionality that is beyond the utility of automated testing (such as hover/accent colors and such). I'm doing automated testing just below that level at the actual business/conceptual logic (as I'm really not interested in using Selenium or such to simulate clicks and the like).
Regarding the "re-frame way": the way I see it is it is nice to have the sub/handler mechanisms in place for when you need/want them but I'm no fan of blind rote and I think a more balanced hybrid approach is attractive. As Shaun mentioned, if you are using / consuming components from other sources, your app is already doing this.
@superstructor: and actually now that you mention it: perhaps "is it worth testing?" is a good proxy for "is this worth making a subscription & handler for?" and/or "is this worth putting in app-db?"
@samueldev I don't see anything wrong with the wipe-everything-below-this
approach
In response to an event like :parent-change
... it seems to make perfect sense for the handler to modify app state in various ways. Cleaning up the old parent, preparing for the new parent.
@johanatan stepping outside the architecture is, of course, absolutely possible. But as Rich Hickey says "Programmers know the benefits of everything and the tradeoffs of nothing" . There will be tradeoffs to choosing to break the fundamental architecture.
We find that sticking with a certain discipline around state very useful. That discipline is reframean in nature. But each to their own.
I think I have a fair grip on the trade offs here and they seem quite reasonable/livable
thanks for your input @mikethompson I appreciate it
Or to put it another way: how many actors/agents/controls/subsystems/components/entities care if one of my buttons is currently hovered or not?
This type of separation of concerns/encapsulation has served many GUI systems well over the years
@superstructor: For the case of common view with 2 different data sources, I've solved it before by refactoring the re-frame control logic up a level and so that I'm passing the problematic data in as an argument to a basic reagent component - so in your example, the emails component would have pending-emails passed in by the parent. It can certainly introduce other issues, but in my apps I've found that every time I want to use that pattern it's a sign that I've made a wrong decision somewhere (which doesn't mean you have, as there are tradeoffs for doing it that way that may not work well for what you need).
interesting, thanks @shaun-mahood
@johanatan: I usually look at it as a question of whether I could spin a portion off as it's own common component, or if it only makes sense in the specific app - things like button hovering certainly make sense as a concern that a common button component could deal with on their own.
why is it that reg-sub doesn’t provide something similar to interceptors ala reg-event-db/reg-event-fx; e.g. being able to use something similar to re-frame.std-interceptors/path
for subs ? or being able to change query-v
.
The equivalent of path
is to use another subscription
(reg-sub
:something
:<- [:other] ;; this is the equivalent of path
(fn [other query-v] ;; first param supplied by [:other] subscription
....))
But no alternative to changing query-v
good point, path was a poor example, maybe there are not enough real use cases for it to be important.
(.log js/console "are they equal?" (= selected-climb-id (:id %)) selected-climb-id (:id %))
@samueldev one of them will be a string and one an integer
They print the same
I’m finding myself writing duplicate filter logic all over the place (the filter logic for "find X by ID" is needed in the plain ol' “give me X by ID” sub, as well as in other subs that are derivatives of and/or are compositions of multiple “find X by ID” subs)
@shaun-mahood: yes, that's precisely the guiding principle I'm using as well. Of course sometimes things don't end up being as isolated as one first expects (or vice versa) and adjustments need to be made but these types of program transformations are super easy in Lisps anyway so I don't really mind it
@johanatan: yeah, the flexibility is fantastic. I've found that in general it's way more possible to fit things around the problem than what I used before clojure.
@shaun-mahood out of curiosity, what have you used before clojure?
@johanatan: Primarily C# and JavaScript for more substantial work
html debugger window is fully generated, you don't need any configurations, just re-frisk lib
one thing, i pass the atom in the debugger window, it dereferred fine, but reagent doesn't update it, i decided to pass it in the window using reagent function - next-tick, but it calls only once, what do you think, what should i use to frequently pass this data? on the demo i'm using setInterval, but it's not good
@andre good job! Will this be part of data-frisk
or standalone? I use cljs-devtools
at the moment for this use case
this is separate lib https://github.com/flexsurfer/re-frisk,
oh ok cool 😄