This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-06-22
Channels
- # beginners (8)
- # boot (41)
- # cider (1)
- # cljsrn (2)
- # clojure (91)
- # clojure-dev (34)
- # clojure-gamedev (3)
- # clojure-germany (6)
- # clojure-greece (324)
- # clojure-japan (2)
- # clojure-miami (4)
- # clojure-nl (6)
- # clojure-quebec (3)
- # clojure-russia (26)
- # clojure-spec (50)
- # clojure-uk (19)
- # clojurescript (147)
- # core-async (5)
- # css (2)
- # cursive (15)
- # datascript (7)
- # datomic (6)
- # hoplon (1)
- # jobs (4)
- # lein-figwheel (17)
- # off-topic (4)
- # om (52)
- # om-next (10)
- # onyx (1)
- # planck (19)
- # proton (1)
- # re-frame (81)
- # reagent (61)
- # spacemacs (1)
- # specter (46)
- # spirituality-ethics (7)
- # untangled (7)
- # yada (17)
I was just thinking … what’s the best way to initialize an app’s db that consists of a bunch of different datasets that must be loaded to satisfy different views?
Is it considered bad form to use componentDidMount to trigger a dispatch that goes to fetch data? Seems a little backwards to me— i would rather the data drive the ui, not the other way around.
But given the 1-dispatch 1-handler paradigm, special case scenarios like this seem more difficult than necessary.
Technically I could have one chunk just “know” that I need to fetch data a, b, c, … z, but I would prefer that a couple top-most level chunks each fetch their own data. This way it seems more modular and less finickey if large changes have to be made.
I could slap together a multi-handler… and each ‘top level’ chunk registers to receive only a few key events as multi-events, such as [:app-initialized], which would give everyone their own opportunity to independently fetch data. However, by doing this i’m not sure the downstream implications of no longer having a strict 1-to-1 handler/dispatch contract.
I dont think it is bad form to use component-did-mount
to trigger a data fetch. Thats typically where most react apps perform fetches as far as I have seen.
So basically you have your subscription in the closure and then a fetch populates that subscription right?
At least that way you have decoupled the data fetch into a handler that can be reused elsewhere
Perhaps - yes. There’s mention of such strategies here https://github.com/Day8/re-frame/wiki/Alternative-dispatch%2C-routing-%26-handling#multiple-handlers-for-the-one-event but not a full fledged flow.
I mean thats how redux works as well
dispatch in component-did-mount that triggers an action
Ehh i’ve found that to be quite painful at certain points, and hence why i’m looking for alternative solutions.
Something like redux-saga makes redux more bearable, but there are a lot of things made more difficult the ‘reframe way’ imo.
Which is why i’m such a fan of reframe… it’s the core tenants but with a whole lot less code and fewer pain points.
This is just one such area I haven’t explored a lot yet, was hoping someone else already solved the problem.
implementation wise, maintaining a runtime of ‘registered multi-handlers’ isn’t too bad, you just don’t get a lot of control if all components register at compile time (essentially) via someting like (reframe/register-multi-handler :some-event (fn [] …)
I would probably just have bare bones fetches then higher order dispatches for the particular scenario
that call the bare bones / lower level fetches
which is what I think you are proposing
I would just be blocking in the higher level version if I needed all async calls to come back
using core.async or something of the like
so init-app would call x async calls and block until loaded...but the x async calls are each themselves individual dispatches or fns at a minimum
that’s an interesting thought… a set of higher-order coordinators that understands ‘foo needs a, bar needs b, baz needs c…’: and they capture the single event, redispatching more appropriate low-level coordination
thats basically what I am doing currently for such things
i think that could cover most cases. the single most annoying one, though, would be the [:init-app]
.
coordinating handler that would probably just update some attribute in loading? state
it’s pretty painful to have a giant blob that knows each and every component in your app on startup
I guess im confused why you need all that on init 😛
well I suppose it depends on your app I just can't imagine needing to load like 10 different ajax calls on initial load
good point. i probably don’t need much more than a handful of datasets fetched initially
I would hope the service could be condensed
in a similar vein, what are you doing to handle initializing of a particular component’s “default state” — things like app-db: {:higher-order-a {:loading true} :higher-order-b {:initializing true}}
?
like an individual reagent component state?
right now i’m just directly-invoking a convention module.db.init
function looks like (fn [db key] (assoc db key {initial state}))
it’s still fairly coupled, but at least the guy receiving [:initialize-app] doesn’t know the data shape of other higher-order components, only that they exist
I have some high order fns that multi args and assoc-in / update-in the state
at the top level I have some generic updaters
handlers*
maybe a little confused as to what you are talking about though
well, my exact use case is the very first moments of the app— (defn ^:export main [] (dispatch [:initialize-db]))
you could also use the dispatch-sync hack
so I have stuff like this at the root handler level
but I try not to use them per se
I use alias's
I guess if there was something to call it yes
I dont think Im answering your question though lol
to my previous point...there’s a single handler registered to receive that :initialize
, but I may have 5 ‘chunks/views’ of the app that have some default state (that’s not async, doesn’t have to wait for an http response to populate)… but I don’t want that single handler to “understand” the shape of those states, because that’s really coupled. my solution is to simply do something like
(reframe/register-handler
:main/initialized
(fn [db]
(-> db
(foo/init :foo)
(bar/init :bar)
(assoc :main/initialized true))))
which isn’t perfect, since there’s still hard references here.why cant the views populate themselves on demand
do they NEED to be all called on init
I dont see why that is the case per se
the views should just send their own dispatch calls and populate a target?
not all of them, but certain ones, yes. otherwise I end up building reagent view components that are overly defensive
for example, if I had a component that renders something different based on a (condp = @context :foo [stuff] :bar [otherstuff])
why wouldnt the dependency just be reactive on the @context
why does the @context need to be there? I would think there should be a nil state handling
i.e dont render it
or something
is this like some role based thing in your real app?
that’s what I was getting at with ‘overly defensive’. in this particular case I suppose the nil
:else isn’t a burden.
like my init-db would be dispatching to set that @context if it was needed or the main page would
that would then trigger the dependent components to load bc they would be subscribing into that data
I think we are saying the same thing I guess Im just not seeing the 'defensive' problem
sorry my simple mind might not be following 🙂
perhaps i’m just being lazy and don’t want to code up an extra view for each component if I don’t have to
I mean what I am picturing with your @context example is how I would know what component to load based on URL
initially the app does have a default state...not logged in...so id load the login page
ther emust be some default state
if context isnt set
two sides to the same coin - i would argue that the context must be set for the component to exist
in that case context must be set to a value that would make a component exist 🙂
but at this point i think it’s just preferential— either dispatch something that initializes that slice of the app-db, or invoke a function that does it, or handle the nil case
good talk though, @sbmitchell … thanks for hearing me out
good luck~