Fork me on GitHub

looking for a workaround for using the same interceptor chain on reg-event-db and reg-event-fx functions. Anyone done something clever for that?


You should be able to use the same chains on both


For example, [debug (path :something)] will work with both reg-event-db and reg-event-fx


I upgraded (not sure if that mattered) and it works just fine now.. <_>'


I wonder why I was under that impression. 🙂


I see - the trick is to realize reg-event-db gets the db only, rather than the world (context?). and the path interceptor will give you the path in the :db key in the world (context?). Right?


I think about it this way: - both -db and -fx are given a coeffect as the first argument - with the -db variety the coeffect is JUST the db - whereas with the -fx variety, you get the full coeffect which mgiht contain other "inputs"


With the -fx variety db is available via the :db key


>Third, we believe that FRP is one honking great idea. You might be tempted to see Reagent as simply another of the React wrappers - a sibling to OM and quiescent. But you'll only really "get" Reagent when you view it as an FRP-ish library. To put that another way, I think that Reagent, at its best, is closer in nature to Hoplon or Elm than it is OM.


Isn't that statement invalid now that ELM has leave FRP?


Hey @lockdown. My interpretation (as a re-frame user and interested Em observer) is that Elm's current model is actually much closer to re-frame than their old model - my understanding is that they've moved to subscriptions and away from explicit signals, and in the move it sounds like the majority of actual use remained similar. Elm also seems to use the FRP term in a pretty academic and well-defined manner, where re-frame is much looser in the definition (my favourite being FRP-ish as above). Not sure if that helps you or just confuses things more, but I think it's an interesting thing to discuss. The other part of that statement that may need amending now is the reference to Om - it's got a lot more going on now beyond acting just as a React wrapper.


@shaun-mahood - agreed is much closer to re-frame than om was. I am still going to try and convince my team to drop in favour of re-frame though.


> Re-frame is impressively buzzword compliant: it has FRP-nature, unidirectional data flow, pristinely pure functions, conveyor belts, statechart-friendliness (FSM) Has anyone thought how they might actually implement (or implemented) statecharts over the top of re-frame?


And have a look at this talk from Clojure Remote:


@andre.richards - thanks. I had seen it before, but not before I was familar with re-frame. So I will revisit it.


I wonder if since 0.8 there isn't a neater more idiomatic way to do it than stately. Perhaps using interceptors


just saw new docs for 0.8.0 and wanted to say THANK YOU to @mikethompson and the rest of day8 team. it's really the best CLJS lib w.r.t. docs and clear reasoning


it's so refreshing to see the thought process behind the way the framework is structured! The lack of such open reasoning was one of the reasons I didn't feel comfortable with Om(Next); David is a very bright developer, but you guys are doing it at the whole new level with this project


@am-a_metail have a look at it is implementing a certain kind of state machine.


But it certainly isn't full statecharts


That was left as an exercise for the enthusiastic reader


@mikethompson - yes that was what I was thinking of as inspiration


Hello. Is there any approach on how to do conditional side-effect in reg-event-fx? For example based on some validation i'd like to decide if i want to send a message to the server. For me simplest idea is to split handler, but maybe there's another approach with queue/stack transforming?


@nidu Can't you just decide in the event handler based on the result of the validation whether to put the side effect in the handler result?


@mbertheau oh, yeah, it seems i misread a bit. Thanks, shame on me


So, is the consensus on re-frame and devcards that they’re a no-go due to re-frame’s global state?


I'm trying to do a POC on re-frame usage in an existing Reagent project by sneaking in re-frame. I thought I would designate an r/cursor to be the re-frame app-db, but I don't see any way to designate the app-db?


In my team, we're debating the pros and cons of having a single app-db and queries/handlers that act only against the single app-db (re-frame) and having an app-db which can be sliced into smaller areas (such as with cursors in Reagent vanilla). I would like to see how this is handled in a larger application with re-frame - for example, simple unique naming of queries seems in my mind an impending obstacle upon adopting re-frame. Does anyone know any larger apps which could show me the light? 🙂


@reefersleep to avoid clashes in the handlers and subscriptions i’ve followed the pattern on re-frame's wiki and happy with it so far.


@jmayaalv thanks a lot! That's much simpler than I thought.


does a subscription ever get re-run if it’s made outside of a component?


Can anyone recommend a FRP framework for the server-/Clojure-side, that works approximately the same way as re-frame (in regard to db/subscribe/dispatch, not the reagent-stuff of course ;))?


Love this project, but wanted to especially call out the documentation as awesome. Informative and pleasant to read (release notes for 0.8.0 reminded me)


@luposlip: Might be worth taking a look at if you can, it has a lot of good info along those lines and is an excellent read. It's on Safari books as well. If you don't want to get the book I can take a look through it again and see if any libraries jump out at me, but I've not used any of them on the server side.


@am-a_metail How are things going with Are you using it for all the GraphQL type stuff? I'd be really interested to get your opinion on why you want to move from it to re-frame.


Thanks @shaun-mahood. Will take a look at it!

Chris Bidler17:08:29

I don’t want to @ mention him since he’s offline but that pointer to the 0.8.0 docs mikethompson pointed out last night was super good

Chris Bidler17:08:27

that was the first time that recommends itself to my memory in almost two decades of programming where I came up with a solution for something, complained “ugh, this is not as pure as it could be” and the response was go look at the release notes for a thing where we solve exactly that problem in an elegant way

Chris Bidler17:08:47

really really top notch work IMO


I have a dissenting opinion on the 0.8.0 stuff. I'd like to be blunt. Also, it may be that I'm just too stupid to understand why it's done this way. But not sure where/how to have this conversation


I think the focus on events is wrong. The focus should be on data, (aka: state). When the state of the app-db is in such-and-such condition, exectute this function.


I know there is a sentence at the end of: that says: A motivated user might also produce a full-on FSM version of this effects handler. But a kind of FSM isn't hard. Perhaps it would break the ability to play the app-db backwards, but the trade-off of requiring the user to think in terms of events versus just the plain old data state of the app-db, seems like not the best tradeoff.


I'd have done the design like this: (1) allow the user to create predicate functions that get run on each DB update. When true, run the supplied transition functions that move the app-db from one state to the next.


I almost implemented this in my own implementation doesnt use a predicate function but just specifies when data transition functions depend on. Then I let the user implement any more advanced state logic in their transition functions. Like user is logged in and their role is Admin...etc...then do X.


My main complaint is i feel we've moved from the simple concept of a user having to think about which states the app-db is one where a user is required to think in abstract events. Like the best is data, then functions, then macros...being the least good.


@fenton: Is your opinion based on the 0.8.0 changes, or re-frame in general? Did you work much with the older versions? I think it's an interesting conversation to have and want to understand a bit better where you're coming from before I start talking about it.


yes. i used the pre .0.8.0.


then i read what 8 is trying to do, and see its very similar to what I built on my own to handle the real issue of what do do about non ui affecting states


which is a websocket server calls etc...


the UI affecting (reactions) are brilliant...its a simple conceptual model...register a subscription to a data location, when it changes re-run someting. That model should be exactly what is used for non-ui affecting things too.


its a brilliant simple model. events are (kind of nowhere to be seen) its simply stating what DATA changes...redo me.


brilliant. but now we are focusing on events...which is an abstraction, and I argue an un-necessary complication, over the clear simple data state, which is the simplest thing for users to understand.


people grok: When these stateful conditions apply. Example: user is logged in, aka: their email is set in the app-db, do X. Abstracting this to events...imo doesn't by a significant of power in exchange for the added complexity...


whats the benefit of going from a noun to a verb model?


@fenton: Give me a few minutes to gather some thoughts - I have a couple bouncing around somewhere that might be worth typing out, but we'll see...


the existing reframe is very noun centric


sure @shaun-mahood thanks for entertaining the thoughts...


i could be totally wrong too...this is just my gut instinct.


I'm trying to wrestle with a deeper understanding of the library and changes too, it's a good conversation to have no matter where it starts or ends up I think.


ok @shaun-mahood just @ me because I'm on another page, and wont check back here unless there is an @fenton happening 😉


kind of what I'd like to see is a hook like after-db-changed, then we can inspect the state of the app-db and run it against our rules...then when the rules match, a predicate hit, we execute the associated state transition function...thats what I'm calling it, but steps that will likely update the app-db again. These are kind of like tiny computer programs that get run when a certain state is arrived at...a lot along the line of go-loops in core.async...


but i dont like the predicates being based on an event abstraction...seems un-necessary...should be a data state that is the precondition for running a function, not an event...i dont think.


@fenton: It seems to me like the only place things have changed in 0.8.0 is the interaction with things that are external to your app-db, agreed?


@shaun-mahood my feeling is that 0.8.0 is an attempt to deal with non-UI stuff. like pre 8 handles UI effect perfectly.... but so much about a web app is non-UI. like all backend comms. pre 8 didn't have a mechanism for running reactions if those reactions weren't tied to a UI state...all the react stuff.... because anything tied to a UI would reaction to db changes...that was the whole point. however we want reactions that aren't tied to the UI...i.e. when a user logs in, we aren't just updating a UI element...we may want to change the page from the login page to the home page or something...this is a bit more that just a change in UI...its taking a user id and password, seeing if they exist, if they do then do X else do Y....


but 8 has pulled all this into a world of events...when the world of nouns...i.e. just simply the state of the app-db is what should be driving all the reactions...


so all 8 had to do was add the ability to run reactions that had less to do with the UI in a react sense and were just generic reactions to data state.


that could do back-end comms etc...


that is the powerful and simple abstraction that made reframe popular...


but websites are SO much more than just simple UI reactions....


adoption comes from simple but powerful concepts.... we use clojure because it has immutable data-types...its a simple concept...with profound consequences...


we need to keep concepts a user must understand SIMPLE.


@fenton: Ok, I think we're at the same starting point - both pre and post 0.8.0 handle the UI part well, and the issue is figuring out how to deal with everything else. I don't think 0.8.0 took anything away as far as capabilities on the non-UI side, but has added some specific options related to it. Still in agreement?


thats the power.


yes tried to take care of the non UI 'reactions'.


but i think it lost its way....pre 8 we had UI reactions that are JUST based on data... basically...that was a powerful concept.


i subscribe to a data location....boom thats it!


Ok, so with that as a starting point, here are my general thoughts (based on my pre-0.8.0 usage and understanding of the changes in 0.8.0, but not working with it yet).


As long as everything was contained in the app-db and UI world, it was pretty easy and straightforward - render a view, user input fires events, and subscriptions to data refreshed the view.


so what i argue for is the same abstraction...just subscribing to locations, when they change, REACT ( i.e. register a subscription ) that does non UI stuff. whatever that may be.


okay just @ me ( you are deep in thought/type) 😉


@fenton: Any time user input caused an interaction to the outside world (most common for me was the requirement to pull some new data in from an external API), the handler that dealt with that input had to be given an extra task. Here is one example (might not be exact but should be close enough) - User clicks a button, it dispatches some event - That event changes the state of the app-db - :active-page is changed, and it dispatches another event. - That event requests some data from the web API, and the ajax command contains a dispatch to one event in case of success and another in case of error. A :loading flag is set in the app-db. - If the api-success event is dispatched, it populates the relevant app-db data and clears the loading flag. - If the api-error event is dispatched, it populates some app-db error state. So everything in the old version is driven by events already when it comes to the external communication and populating the app-db. Subscriptions to the data inside the app-db drive the UI state. As far as your example above for a user log in (log in, update UI, change page, etc.) - I've done very similar things in the old versions with no issues, and I expect they will get easier and more straightforward in 0.8.0. I've not needed to inspect or look for changes in the app-db outside of the context of the UI and dispatched events, so I've not tried anything in that direction, but I can't imagine it would be that difficult.


@fenton: I'm also not clear on the issue between nouns and verbs in your comments above - in pre-0.8.0, the data was the nouns and the dispatched handlers were the verbs. In post-0.8.0, the data is the nouns and the dispatched handlers are the verbs. The big changes I can see are that when you are dealing with the verbs now, you have the option of passing additional data in a different manner and passing additional verbs to be called in a different manner. I might need some clarification on that part to understand a bit better what you mean there.


now we are subscribing to This seems unnecessarily complecting. Previously we subscribed ONLY to data. That model was perfect for UI, why isn't it perfect for non-UI. Of course everything can be done, but why not keep simple models. Now we are subscribing to events... Events are like function calls. They are inferrior to data. Your scenario could be easily be rewritten like so: User clicks -> updates DB. Thats all the event does, just update the DB. Now somewhere else (FULLY DECOUPLED from the DB event that updates the DB) some other logic needs to get run. We can handle this in two ways. (1) we can have an event...whats the event? PAGE-CHANGED, or PAGE-CHANGED-FROM-LOGIN-TO-HOME. Having one event dispatch another event couples the two together and isn't a good design. I'm not saying it can't be done, of course it can be done...but we want SIMPLE. chaning event dispatches couples the logic all together...better to have logic fully decoupled. That was the power of the UI model. We dont want to know apriori what a state change (app-db change) will imply in terms of UI update...and also we dont want to hard-wire ahead of time what events call other events...we want everything to come back to the state of the app triggering things...not events triggering events triggering becomes spaghetti..


its like pure functions versus side effecting ones...


i'm sure i'm not articulating well...


we never said...user presses button, now go to this UI element and update it, go to this other ui element and up date it... we DECOUPLED the setting of state: event handlers, and the REACTION to them...this was the power...


@fenton: Ok, I think I get what you're saying.


sorry it is sometimes tricky to articulate this stuff...and its a bit gut level...and abstract...and hard to talk about...for some reason...


I also have to confess I never quite understood what additional value events brought to the table over just swap!, even in reframe 0.7


an interesting discussion btw


some reason why you'd want events: 1. adding middleware, 2. replaying the history, 3. undo


2 and 3 don't seem too exciting to me


4. Modeling side effects in some oberservable/testable way


@fenton: I found in my pre-0.8.0 experience that there were some situations where it made sense to subscribe to data and react to changes on that data, and others where it made sense to define chains of events. The addition of the -fx form of handler seems to me like it should improve the experience of writing those chained events, and the changes to middleware and the coeffects seems like it should improve the handlers and middleware that require some extra data that isn't readily available in app-db. None of it, though, takes away the ability to store all of that information in the app-db as state and develop additional logic based on that state.


@martinklepsch, making it easier to write unit tests is a plus


and I guess you can log out the events, giving you a nice way to trace the execution of the program


so given those advantages of events, what would be an example where the 0.8 additions help?


e.g.,: user clicks -> request resource from server -> based on response, send request to (another?) server -> based on response update ui


I read all the effects/coeffects stuff and got pretty hooked, really just all about modelling side effects without actually carrying them out


I'm not saying do away with need events. I just think events should also be able to be triggered based on a given state of the app-db. Thats the abstraction of pre 0.8.0, but it only works for UI. Need it for non-UI stuff too.


can you give an example for non-ui triggers?


check if a users username and password are valid with a server.


i have no comment about testability...the idea could ruin that, i dont know...


if username/password are correct, set a flag in the app-db saying :logged-in true else set a flag in app-db :login-failed true


@pesterhazy: Biggest advantage from my previous usage is the better definition of both what is required (coeffects), and the more concrete definition of event chains (effects). The difference for your example is documented pretty well at, but not sure if that's what you were asking.


now I register another event to the DATA :login-failed true, to which I could set the DATA :active-page to the VALUE :failed-login-page...blah blah blah....


@shaun-mahood, interesting, I think I read that at some point


i wonder if this idea doesn't make testing easier... I'm saying set the app-db to some value...your Verbs occur to transition the app-db to some new value. That is the essence of testing no? Input state, function, output state?


its not pure... input an username/password checks in DB (outside world) the user may or may not be registered in DB, so result can be different, but you could just consider the DB as another input then its pure again?


@fenton: That seems like something that can be dealt with very well in the current model to me. - Click submit on the login page - Handler fires an event to check login info with server and sets a couple data fields (eg. {:page-location :secure-page1, :loading true}) - When the login event returns, it sets {:logged-in true, :identity "User1", :secure-access :level5, :loading false} - Your view has been watching the data and responding throughout - when logged in under a user with the right level of access and loading is false, it renders the page I think for this example you would also want to fire another event to request the data from the server with the stored credentials - from everything I've seen, real security of that sort can't be relied on if it is client side only, so you would probably need a lot more communication back and forth to validate data requests using some type of secure token in the app-db.


@fenton: If you haven't looked into it much, might be interesting to you - it's got a really interesting and well thought out approach to communicating with servers and hydrating client side data. I think a lot of it is quite related to this conversation.


my method would be 'slightly' different. clicking login would ONLY update the username/`password` fields of the app-db. Decoupled from that is an event that is registered to the fields username/password. Just like pre 0.8.0 subscription handlers for UI. When those values change run the login event. It queries the DB, gets a result and sets the app-db accordingly... :logged-in to true or false...


yeah. I just wish the om folks had a canonical example of how to connect to datomic. Their doc for remote synchronization is laughable. And the answer is: use untanggled... Went down that road and the author of untanggled is...well I shouldn't really say here...but its not something I'd recommend to people.


@fenton: If you haven't, try building an app that way - I think it's totally possible and well within the scope of re-frame. That's how I started with my first app and I ended up tearing it all out as it got more complex, but it could be that was just my inexperience.


yes I am building an app this way, with pre 0.8.0 stuff, and am okay with it. I've got the core of it working with 65 lines of code....I could clean up a bit and share... but I'll post what I have here as an example...


@fenton: Throw it into a gist if you get a chance, I'd love to look at it.


notice state-transitions-init Thats where I specify the data that functions depend on. You see this is very much like what 0.8.0 is doing, but I depend ONLY on data, not on VERBS/events.


That is the model of pre 0.8.0 vis-a-vis UI and its a powerful model that everything can be developed from, and my suggestion SHOULD be developed from....thus this long conversation. I have no comment vis-a-vis @martinklepsch and @pesterhazy about testing...i feel that is important and am not sure that this approach makes that harder or not... I care MOST about non-UI reactions...less about replay, time-travel etc...


hmm, guess that should be (filter :active? @apps) actually


@manutter51: If you're using v0.8.0, the original docs aren't up to date yet I don't think. reg-sub does the reaction for you.


@manutter51 reactions are re-run when their inputs change. I would pull out the active apps, then wrap them in a reaction and return that.


@manutter51 something like that....


@manutter51 i dont understand the bit about: and I want to use ⁠reg-sub⁠ to build out the signal graph.


okay back to work....


@fenton: Good idea. I'm going to mull over this conversation for a while and see if I come up with any additional thoughts.


@shaun-mahood [5:35 PM] > @am-a_metail How are things going with Are you using it for all the GraphQL type stuff? I'd be really interested to get your opinion on why you want to move from it to re-frame. (edited) Sorry about the delay Shaun - Actually finding to be a powerful and very clever tool. My issue is that it's not explicit enough. For example, there is a function to get the query of a component in order to embed it in within another component. takes a look at this and alters the query of the components involved. Simply taking the output of the (get-query component) -> [:foo ] for example, and placing it in the query of the original component has a different effect. This feels very impure and worse, isn't obvious. It is tucked away in the documentation that is the case but it just seems like this kind of behaviour should be obvious.


That sort of thing pervades through I am all for clever solutions, but never at the cost of explicitness


It does share many of the re-frame approaches and you can see where it seems they might have influenced each other


But honestly our codebase has descended into madness in short period of time. Yes we're an inexperienced team, but I think om/next doesn't offer much in the way of structure and documentation (yet)


And as several people have noted already today - the documentation for re-frame is excellent


@am-a_metail: I tried to get into the original om and it just didn't click with me, but I found re-frame easy to understand as a beginner and was quickly productive with it. It was also really easy to refactor as I realized all the dumb things I did at the beginning, so it's one of the few codebases where I don't totally hate it when I look back after a while.


@am-a_metail I like to think re-frame is just a better om-next with more ease-of-organization 😉


I think working with om/next is actually a really good intro to re-frame as you can see how it should be done


@am-a_metail: As in is how re-frame should be done, or re-frame is how should be done?


re-frame is how om/next should be done 🙂


It has the right ideas, but the wrong execution


The wrong execution for our team I should say


Some might find otherwise


Perhaps I can paste an example code-snippet


I can hardly bear to look


I've worked with a lot of perfectly good libraries in other languages that just never clicked with me - looks super interesting to me but I don't have the right problems (eg. requiring GraphQL etc.) to make it worth diving into right now. Seems to me that re-frame solves about half of the problems that does, though.


My sentiment exactly - re-frame just "clicks" - Or at least seems to. I haven't written anything serious in it yet


And we're not really taking advantage of the GraphQL stuff


@am-a_metail: Oh yeah, if you're not doing GraphQL in it seems like you would be wasting so much potential.


Also, the older docs and new v0.8.0 stuff aren't in sync yet, so there's going to be a bunch of translating back and forth as you're learning things. Hopefully that will be fixed in not too long, but I don't think there's anything really bad if you have a basic understanding of the old and new information.


I actually really like the async-flow stuff from 0.8.0 - reminds me of:


Right better get some sleep or I'll be dreaming of StateCharts again


@fenton re-frame 0.8.0 doesn’t remove anything from you. You can program with it just the same without ever touching any of the new stuff. re-frame still fundamentally has the principles where dispatches (events) modify the state of app-db, which triggers UI updates, bringing it to a quiescent state. What you’re talking about with login setting state in app-db, and a handler subscribing and rerunning based on that is now possible with fx handlers (I think), but I would argue that the more re-framy way to do it is to look at what caused the DB to change, and run the login there.


Changing the world from a subscription is generally not how you want to do things, instead look at what event caused it to happen


What you’re describing is all possible, it’s just not the design choice re-frame has chosen


yeah...I just thought the concept of watching a set of data and then reacting (in a non-UI way) extends the already awesome UI reactions...


@danielcompton can u expound a bit on why: "Changing the world from a subscription is generally not how you want to do things" is bad?


is it because can lead to signal looping?


gotta go to meeting, will try to write something up later


@fenton: Ok, thanks. I was concerned about having one reg-sub for all the apps, then a second for a subset of the apps, for fear that would lead to unnecessary duplication. For just 2 subscriptions I doubt it's a problem, but what if I start having multiple overlapping subscriptions like A is a subset of B, which is a subset of C, etc, etc.


trying to get a feel for the best practices in general


@manutter51 i have a different best-practice than others 😉. I have ONE subscription and ONE handler ONLY. I'll post them


heh, that'll work 🙂


i didn't like the proliferation of event handlers and subscriptions... but maybe I'm weird...


the handler looks a bit weird because I do a few extra things...when i action setting data...


then i just run: (dispatch [:set [:some :data :path] "value"])


and @(subscribe [:get [:some :data :path]])


personally i feel handler and subscription proliferation to be an anti-pattern.


@ me if you want my attention 🙂


I'm too new at it to have solid preferences yet, but so far I kind of like having them separate so I can modularize them and put related subscriptions/handlers in a smallish namespace


but we'll see how it goes