This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-22
Channels
- # beginners (240)
- # boot (23)
- # bristol-clojurians (3)
- # cider (101)
- # cljs-dev (52)
- # cljsrn (17)
- # clojure (212)
- # clojure-dusseldorf (2)
- # clojure-greece (2)
- # clojure-italy (9)
- # clojure-russia (1)
- # clojure-spec (91)
- # clojure-uk (33)
- # clojurescript (164)
- # community-development (23)
- # core-async (24)
- # core-logic (9)
- # cursive (18)
- # datavis (1)
- # datomic (119)
- # emacs (13)
- # events (1)
- # figwheel (2)
- # fulcro (86)
- # graphql (1)
- # immutant (5)
- # jobs-discuss (6)
- # leiningen (19)
- # lumo (46)
- # nyc (7)
- # off-topic (23)
- # parinfer (15)
- # pedestal (3)
- # planck (32)
- # re-frame (48)
- # reagent (75)
- # ring-swagger (13)
- # rum (32)
- # shadow-cljs (402)
- # spacemacs (5)
- # specter (3)
- # tools-deps (11)
- # unrepl (20)
- # vim (135)
- # yada (3)
I understand how to load data from server using reg-event-fx
. But then my view components need to dispatch this event on load. Is there a pattern how to trigger AJAX when a subscription is dereferenced? Or should my view components dispatch events when rendering and a subscription returns nil
?
@witek Why do the view components need to dispatch the event? I find it a lot nicer to trigger events that load data from the server when a user navigates to a certain page, or clicks a button etc
e.g (using secretary in this example):
(defn app-routes []
(defroute "/" []
(dispatch [:page-entered :main]))) ;; Where :page-entered for example sets the current page to :main and loads appropriate data from the server
@witek "load on mount" is not idiomatic to re-frame
as an example of "loading things on page change" instead of on component load...
(routes/define-route!
:frontend.product
{:name ::page
:url ["product/" :id]
:component page
:init-fx [::init]})
::init
being:
(rf/reg-event-fx
::init
(fn [{:keys [db]} _]
{:db (assoc db state-key {:quantity 1})
:dispatch [::fetch (routes/ref-from-param :id)]}))
@curlyfry Your solution requires the event handler to know what view components are on the page. This seams very problematic to me. Especialy when using generic cross cutting view components which are plugged in to nearly all pages. Or when these are enabled/disabled from the main menu. Then the event handler needs to implement all this logic too.
I have that problem too and I used to load things on component init (form-2 components) but it's definitely better to either:
- pass whatever data it needs in the props
- have that data in the db, and pass a db path or subscription
- prepare the given component on app or page load (define a dependency of page
on component
and dispatch whatever is needed on page load)
- define an init-fx
for that component and require implementors to dispatch it before using the component (this being the worst option)
This way it seams very difficult to implement reusable view components which are independent. I had view components in mind which are just referenced. And the components then themselves subscribe required data. The user does not have to know all these internals of the component.
I find the app much easier to reason about when all loading of data, view switching etc are event driven
agree
If you have a :show-my-component event, that event should probably load the required data (if needed)
and as re-frame devs always say: events should represent user intent and should be dispatched as the result of user's actions, those being: entering the app, entering a page, clicking a button, ....
So if I have a component which displays a page-view-count with data from the server. And this component is visible on 9 of 10 pages. I should implement the data-loading in 9 event handlers? And if the visibility of this component depends on some url-parameter, this if is also repeated 9 times? Seams odd to me.
and when the component changes and needs more data, then I have change almost all my event handers? Just because one view component changed?
@witek re-frame encourages you to think this way: 1. The views are simply derived data (derived from the current application state) 2. Views do not "cause things to happen". They are not imperative. 3. On the other hand, events come with mutative intent. 4. Events capture a user's intention. I know this is a different way of thinking, but I promise you that once you get used to it, it works better than making views "agents of change" :-)
So, all "changes" should arise out from events.
In fact, the ONLY reason views changed was because of an event
you don't need to change "all your event handlers" because the event handler for loading whatever data that component needs is just one event, you dispatch it in the pages and then it does whatever
So within the event handler which is causing the state change, which reflects in a UI change, you make THAT the place for triggering the "whatever is necessary for the view"
I would: - make the component pure - define an event for loading the count (::load-count) - define a ::load-url-params-data event, which would parse the URL params and decide to dispatch some events, ::load-count possibly one of them - dispatch ::load-url-params-data when a relevant page is accessed
no duplication and no need to change things everywhere
The duplication is in "- dispatch ::lad-url-params-data" on all relevant pages. But ok, I get it.
you can also define a set of pages that should implement that, or some fancier mechanism, but this is just a regular programming problem
or implement a global "route-changed" handler and decide if you should dispatch ::load-url-params-data or not based on whatever 🙂
What if loading the data necessary for a component should be done at a more granular level than a whole page load
eg what if you want it to be more lazy than that. It just seems limiting to me that routing to a new page would have to be where all data “bootstrap data” loading is started from. Maybe I’m wrong though.
I guess other loading could happen beyond that, just by some explicitly triggered event. Maybe that is fine. I’ll have to experiment. I think i have a few “bad” components that try to load their own data if needed on a render. Fail.
dispatching events when X component is in the viewport is (imo) doable and reasonable (although not very common), but loading data on component init doesn't help with lazy loading anyway
The events handlers that show/hide your more granular components could also fetch the data they need, for example
I think I just wasn’t thinking it through enough a few times when I ended up putting the init/load event dispatch directly in a component render/mount
It seems reasonable to think there are Ui events happening that could be used to attach dispatch calls too
I also load all data via events. But https://github.com/Day8/re-frame/blob/master/docs/Subscribing-To-External-Data.md seems to be what @witek is looking for probably?
any larger open-source examples of a re-frame app other than the real-world/conduit app one?
See External-Resources
in /docs
For a list of apps out there