Fork me on GitHub

I was talking with @jatkin about derived state in Fulcro, and after a rather long chat I wanted to experiment with an idea I had. There is a long-standing complaint that Fulcro does not come with (out of the box) a facility for auto-updating derived data. Many of the cases, I think, are just as well done in the actual render, and don’t merit the added complexity of such a system. I consider them to be optimizations that trade off for the wrong thing; however, I do admit that there are some cases where derived data is expensive to compute, and Fulcro’s natural facilities make it less that ideal to keep “up to date”. So, long story short, with a simple 4-line add to Fulcro (not released, since still experimenting) I can add support for “transaction middleware”. At that point, it is pretty easy to have a library add in functionality like that. What’s more, if you understand some of the other facilities that Fulcro has (like the internal indexes), then you can get some pretty good results without much code. Here is a sample video (and there is code you can check out and run):

David Pham12:06:59

@tony.kay Thanks a lot for your answer on event driven design. If you code with event systems, do you have opinions/advices/guidelines to make it maintainable?


I think the reframe crowd probably has better advice on that. Perhaps use state charts? The problem with events is that you end up with sprawling chaos if they go beyond a single ns without something to unify them. It’s both their superpower to have potential far-reaching effects and their biggest weakness.


A bit like goto in a way

David Pham13:06:05

I think we can see it like components

David Pham13:06:30

I don't know yet how Fulcro solves the problem, but I am getting interested 🙂


Next experiments video: After sleeping on the “reducers” problem overnight I had a couple more things I wanted to share with anyone that is interested in the problem and possible solutions. In particular, this video talks about two different things that come up for Fulcro users: 1. The desire to have something auto-handle derived data as state changes. You can always just “watch” the state atom and add something in, but I explore some Fulcro-specific details that can be leveraged. 2. The desire to PULL data from the database WITHOUT having to be connected to the reified data graph. I.e. have a free-floating function that can pull data from the DB, render DOM, and be refreshed automatically. This video shows the elements of how those things can easily be added: and the source is referenced from the description.


There are many many ways these could be augmented/modified/optimized. These are not “production ready” demos, but demonstrate that Fulcro is pretty open to extension, and it really isn’t much work to add in you favorite “pet feature”.


In this case, the “pet feature” is something I’d like to see pluggable alternatives for, and perhaps a new ns or two in Fulcro proper. React hooks, as demonstrated, can get you a lot of leverage without having to have any library support.


Those of you that have not played with hooks you might want to watch the video just to see how simple it is to leverage them to good effect in Fulcro.


I'm actually quite surprised how easy something like this is to add. I need to keep digging around fulcro so I can see this kind of stuff.


that’s part of why I wanted to make the video…much easier to “show” sometimes than just “tell”


The last demo in the video where I use a render hook: I’m not sure that’s the ideal place for the render of subscriptions…it’s probably still something that belongs in a more optimal location where state diffs are compared to decide what needs to be updated, esp since those renders can be targeted and need not do a render from root.


The more astute viewer will note that some of these “changes” could lead to apps where you don’t use the reified UI graph at all. Imagine a render plugin that just updates subscriptions (delete the call to kr2/render! and that’s what you’ve got).


you’d instead use a bunch of disconnected “reified subgraphs”


the down-side is that you’d lose the introspection power of the query (which is leveraged to good effect by dynamic routers for example). But it might be a perfectly great answer for some apps.


If I had to guess: I’d guess many people would find that model better. I’m somewhat attached to the reified data model of the view for a number of reasons…but I’m seeing fewer and fewer reasons to make it any kind of standard. A “dynamic router 2” could leverage different declarations to construct the routing graph instead of introspection of the query. Form state would still only make sense if you at least reified the subgraph of the form (which is solidly a better choice).


The reified UI graph gives you something really important that you probably do not want to lose: composable, auto-normalized, initial app state. So I think this trick is mainly interesting “at the leaves” that spring into existence over time. The “bones” of the main app with the various top-level routes and things make sense as a reified graph with initial state. But I can play devil’s advocate and say “you can initialize in the hook”…which is possibly true.


One more note that I did not code up: Pathom is CLJC. The render-step that interprets the query with db->tree could use a pathom parser instead, and then you’d have a way to define resolvers to resolve particular props. You’d have to re-implement the bits of graph traversal that db->tree does. Wilker did that a while back as an experiment, but there was no way to make it as fast as pure db->tree, so we decided not to expand the query system at that time to support it centrally. Note, however, that it is possible to use a Pathom parser to easily “feed” parts of the UI using the tricks in that video.


@wilkerlucio did you keep your experimental pathom version of db->tree??


yes, its on


It seems I cannot set/use :ui/ variables in a defsc-form, is there a way around that?


See query inclusion


Ok, so there is fo/query-inclusion. I guess I have to, e.g., add :ui/message there. I also added :ui/keys [message] to the props destructuring. But I cannot add ui/message to fo/attributes, since this will result in an error. I also can't seem to use either fo/default-values or :initial-state to set a value.


Ideally I'd want to load things like dropdown values like that. E.g. I have this path :ui/dropdown :vendor-types which contains a vector of maps, and I'd like to have that available via this fo/query-inclusion