This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-19
Channels
- # bangalore-clj (2)
- # beginners (217)
- # boot (3)
- # cider (130)
- # cljs-dev (117)
- # cljsrn (11)
- # clojure (99)
- # clojure-china (1)
- # clojure-denver (1)
- # clojure-dev (22)
- # clojure-italy (30)
- # clojure-norway (5)
- # clojure-russia (13)
- # clojure-sanfrancisco (3)
- # clojure-spec (74)
- # clojure-uk (107)
- # clojurescript (40)
- # clr (6)
- # core-async (25)
- # core-logic (4)
- # cursive (1)
- # data-science (1)
- # datomic (62)
- # duct (11)
- # editors (14)
- # figwheel (3)
- # fulcro (12)
- # funcool (1)
- # garden (12)
- # graphql (19)
- # jobs (4)
- # jobs-rus (1)
- # lein-figwheel (1)
- # leiningen (12)
- # luminus (5)
- # off-topic (45)
- # onyx (12)
- # other-languages (1)
- # parinfer (5)
- # programming-beginners (3)
- # re-frame (113)
- # reagent (63)
- # remote-jobs (10)
- # ring-swagger (1)
- # shadow-cljs (31)
- # slack-help (3)
- # spacemacs (27)
- # specter (1)
- # unrepl (44)
- # yada (16)
@mikethompson I wrote an effect handler in a few lines after following the manual the old fashioned way and it all works fine
Could someone have a look into
https://github.com/StankovicMarko/invoices
I feel like i am not using re-frame correctly to me it feels like reagent and it's atoms on steroids. To me it feels like i am using re-frame db as reagent.session is this how it is supposed to be?
also
is this good approach?
https://github.com/StankovicMarko/invoices/blob/master/src/cljs/invoices/components/login.cljs#L25
for some reason i am thinking this is not best practice and that i should be using
something like this https://github.com/Day8/re-frame/blob/master/docs/Talking-To-Servers.md
(dispatch reg-event-fx
which will send request and describe next step, which dispatches reg-event-db
and update db
)
any feedback would be greatly appreciated
Hi, I have a question about event dispatching.
I need to initialize my app-db
with external data, so I am doing something like this:
(rf/reg-event-fx
::initialize-db
(fn [_ _]
{:dispatch [::my/event]
:db default-db}))
The dispatch goes well, but it takes a while because there is quite a lot of data to be loaded.
The problem is when I need to access the data in app-db
from another event. ::my/event
loads the data correctly (I inspected app-db
via re-frame-10x
), but while it's loading it the other events proceed and don't have access to the data ::my/event
have yet to load.
Ideas?@manuel hi, i am not re-frame guru i am learning it myself
but i saw something like dispatch-sync
which basically says oke do this now
but there was a note that you shouldn't do this unless you know exactly what you need
so what i propose is
(rf/dispatch-sync [::initialize-db])
instead of regular dispatch. can't find this in re-frame docs right now but try looking for it
@manuel is that data being loaded being fetched asynchronously? perhaps from some ajax call somewhere?
@lepistane dispatch-sync
docstring says to avoid using it in an event handler, though, that's why I wasn't rely on it
@joshkh yes, via ajax
@lepistane @manuel You probably do want dispatch-sync
for this case, but you need to use it on [::my/event]
, not [::initialize-db]
. Otherwise ::initialize-db
will go off, dispatch ::my/event
and then return before ::my/event
runs.
I think it's ok to use dispatch-sync
in the initialize-db
because that's a special kind of event -- you need dispatch-sync
for exactly this kind of situation
i'm sure it's all good (i don't know much about dispatch-sync
) but i kind of feel like it might be an IO / race condition.
if dispatch-sync was going to solve your problem then it shouldn't matter how much time it takes, right?
if you're directly seeding the initial db from an ajax call then it's not going to work
@manuel right, you do not want (rf/dispatch-sync [::db/initialize-db])
, because that will wait for the initialize step to finish
The problem is that the initialize step is calling my/event
asynchronously, so initialize-db
returns immediately, before my/event
completes.
Actually, you probably want dispatch-sync
on both ::db/initialize-db
AND ::my/event
, to make sure none of them return before your data is loaded.
@manutter51 thanks, I'll try that
Could someone have a look into
https://github.com/StankovicMarko/invoices ?
I feel like i am not using re-frame correctly to me it feels like reagent and it's atoms on steroids. To me it feels like i am using re-frame db as reagent.session is this how it is supposed to be?
also
is this good approach?
https://github.com/StankovicMarko/invoices/blob/master/src/cljs/invoices/components/login.cljs#L25
for some reason i am thinking this is not best practice and that i should be using
something like this https://github.com/Day8/re-frame/blob/master/docs/Talking-To-Servers.md
(dispatch reg-event-fx
which will send request and describe next step, which dispatches reg-event-db
and update db
)
any feedback would be greatly appreciated
got this error in the browser console, though: dispatch-sync was called for [::my/event] . You can't call dispatch-sync within an event handler
https://github.com/Day8/re-frame/wiki/FAQ#2-why-cant-i-call-dispatch-sync-in-an-event-handler
oh yes, as I was saying before, the dostring is pretty clear about not using it in an event handler 🙂
@manuel does [::my/event]
kick off some press to data fetching process, or are you saying it can't see data that should be in default-db?
[::my/event]
is basically only an ajax call to fetch data which, upon success, are loaded into default-db
i'm sure manutter51 is onto something. i'm still a little worried about that ajax call. do you want the ajax call to stores its data before any other events happen beyond :initialize-db?
okay, so i'm doing something similar on another application that fetches loads of assets, and i don't want the user clicking around and mucking things up until they're all settled. i do so by firing this event with dispatch-sync
https://github.com/intermine/bluegenes/blob/dev/src/cljs/bluegenes/events/boot.cljs#L115
day8 has a handy effect for handling async flow: https://github.com/Day8/re-frame-async-flow-fx
but for instance, i don't route to any of the app's sections until i've seen a :finished-loading-assets
event
again, that might be over kill! your :my/event
fires an ajax request. but what's triggering the third event that happens to early too see the response?
maybe you can have my/event fire an ajax request, and that response handler fires the next ajax request?
it sounds like they shouldn't be running in parallel if the second depends on the results of the first
(reg-event-fx
::my-event-1
(fn [world [_]]
{:my-ajax-effect {:url "/items1"
:on-success [::store-event-1-results]}}))
(reg-event-fx
::store-event-1-results
(fn [{db :db} [_ response]]
{:db (assoc db :results-1 response)
:dispatch [::my-event-2]}))
(reg-event-fx
::my-event-2
(fn [world [_]]
{:my-ajax-effect {:url "/items2"
:on-success [::store-event-2-results]}}))
(reg-event-db
::store-event-2-results
(fn [db [_ response]]
(assoc db :results-2 response)))
my-event-1 fires the ajax effect, and when it finished it calls store-event-1-results which updates the db and then dispatches the second ajax event, my-event-2
yeah, a clean solution. Thanks @joshkh. I'm leaving the office now, but I'll try your solution first thing tomorrow.
i was wondering if someone could talk with me about a good strategy for structuring an app, mechanically, that’s designed for growth and isolation. specifically, how do you handle updates to data on a server via the event-handler-server-handler loop, and how do you structure queries to optimize reuse and decoupling?
say for example I have a user-profile page… the data’s easy enough, right? name surname DOB [some other domain-specific account stuff]. generically I could create a user-profile feature that would house and handle all of the user-related data updates. by storing the user data flatly in the db, anyone else could subscribe to this data, and all’s good in the world.
but what if some new feature enables you to change your name, or maybe your address, or some other user-entity-related data WITHOUT going through the existing user-profile page?
all the handlers that exist for updating data are in some other feature, and you wouldn’t want to emit events from :some-new-feature
that target :user-profile/address-changed
.. that would be almost like programming to an implementation instead of an interface.
do you extract out those handlers to a more generic “user entity” set of handlers? then both the user-profile and some-new-feature features would essentially be emitting events to “somewhere else” that handles the data.
in this sense it’s like the opposite of a “shared common query”-- reusing queries is encouraged and helpful, but what about reusing mutating handlers? I think it’s kind of corollary to how people generally go through some interface to access a db-- or at the very least a set of common functions, so that you avoid a ton of db-connections littered everywhere throughout code
@ericnormand you have some great content on re-frame; maybe this could be another subject to tackle in a future post?
it's a great question
I think it basically boils down to how you model your domain
your events and subscriptions should be semantic definition of your domain actions/entities
so if your user can change their name, and that action makes sense in itself, then it's an action you should name
I believe that tying it to a certain view in your app is exactly where people go wrong
they're often afraid of the small level of indirection, thinking "change name" is too abstract, that it should be tied to something concrete, so they tie it to the particular page on the site
that makes it hard to grow or to reuse that action
but effectively modeling a domain is a hard problem
"what is a person's name?", etc
it's not clear
requires some UX work
and that's where people get lazy
you need to be looking for the timeless semantics of your app
like "people have names, and they're strings"
:person/name :string
right?
but if it's "user accounts have names, that may or may not be their given person name", then it's different
:user/name
but I'd definitely never tie it to the profile page, as in :profile-page/change-name
or anything like that
that’s a really interesting take on the problem, almost top-down and not bottom up-- everything that affects your domain is a domain-event and, only if necessary, scope other events that are feature-specific (read: not of domain importance) to a finer-grained event.
yeah, that's a good way to put it
you could more-easily structure your code (again, mechanically) to be able to see “what are all the thingies that change my user domain model”, too
have you read this? https://purelyfunctional.tv/guide/database-structure-in-re-frame/
>Event and Subscription Naming Summary > >Name so you can reconstruct what happened later >Names should reflect the domain concepts not the technical concepts >Events names should capture the intent, not their effects and not the UI action >Subscription names should describe the data, not the implementation and not the >Component
and btw; your new apropos is great. i love the casual-ness, but most importantly the REPL time. it’s a really great idea to watch clojure experts think their way through different problems. you get to see some neat lang features (`cycle`, juxt
) and it’s all very relatable.
awesome
i would watch you guys all day if it were structured like: 10 minutes of new clj developments (releases, libs, news, etc.) followed by 20ish minutes of solving a problem on a repl.
yeah, 30 minutes of conversation feels like it's not enough time for 4 people to say anything
maybe we could structure it more so it's just updates
we've heard people mention they like the repl segment better
maybe we'll evolve that way
while it would be great to just “have a conversation” for a long while, i think the casual nature works against this objective… it doesn’t seem like there’s a lot of preparation going into what you want to say, so the conversation about something new is fairly shallow, if that makes sense
I think also we need to work on the notes/topic selection
the last one was pretty bad
someone added them but the notes weren't descriptive enough to know what they were about
i'd like a rule like "at least 2 of us have to have something to say about it"
or just know that you're on your own talking about it
that’s probably more fair to the panel-- they only spend time preparing for 1-2 topics instead of 3-5
it has to be important to someone!
maybe "strong feelings" should be the criterion
oh, you mean the panelists pick the topics? or you propose topics and would axe anything that doesn’t garner interest?
it would also be cool for the “problem of the week” to be something pulled directly out of a workday (and trimmed down appropriately), as opposed to a random “solve the fib sequence” type of problem
there needs to be at least two people with strong feelings about the topic or it won't be interesting to hear the panel talk about it
yeah, those problems are harder to find
and we've been having a lot of discussion around the simplest whiteboard interview style problems
I think they're good for being small
you can see multiple implementations in the same episode
good point. its probably fanciful to think you can extract a context free problem that’s solvable in under a few minutes on the regular.
thanks for the discussion