Fork me on GitHub

Regarding question about additional resources - I’ve been planning to add a wiki to the fulcro-expo-template repo to document additional tips, gotchas, recipes, etc. when working with React Native and Expo, based on what I’ve encountered over the last 10 months using Fulcro with that platform. But if there is community interest in creating a larger wiki covering Fulcro in general, then I would be happy to contribute to that instead (I.e. a section specific to RN development). My only stipulation is that a) I don’t have time to maintain the entire thing, just the RN section and b) don’t ask @tony.kay to maintain it, because he’s even more busy. But if someone else in the community want to step up and lead such an effort, I’m happy to contribute the RN stuff to “kick start” the effort.

Arto Kalishian05:10:57

I am currently learning Fulcro throughout the official documentation and logging all the questions that come to my mind and whenever I see typos or missing info I mark on them so I later send them all to whoever who maintains to fix. Meanwhile, these questions I had as a beginner can be added to some sort of general Fulcro WiKi or FAQ as you have mentioned. In all cases, I am ready to help but tell me what exactly you need and if I am skilled enough to do it I will.


@mdhaney I’m making a fulcro-native repo this very minute


on clojars. Very light, but PRs welcome.


Only supports Expo so far, but regular native is just a slight modification. I don’t have a project to test with, so I’ll explain/accept a PR if anyone else does.


I’ll open up a Wiki on that repo.


Adding doc strings to the factories in the components ns would be a welcome addition if anyone is looking for an easy contribution.


be nice to know what props the components take…perhaps there is some machine-readble docs we can convert from


Is there a strategy to use when you already have 'lookups' in the app state, and yet they are needlessly coming in from the server? For example a df/load might be asking for LineItem, and a hundred or so are coming back. Each line item has a product, of which there are only a few, and they are already in app state. I would like the client to be querying only the :db/id of the product, and then on the client somehow attaching products to line items. Actually I was hoping this kind of merge behaviour would be happening automatically, but didn't seem to be when I tested.


I guess you are supposed to be using Pathom on the server and putting just the lookup info needed into that particular entity, which is an entity designed with the UI in mind. So line-item/product-name would be being queried for and coming across with every LineItem.

👍 4

The trouble with using Pathom compared to changing the functionality of merging so that for example :line-item/product with a value of just a reference {:db/id 4654...} gets properly merged into app state is that, well, you've disconnected from app state. I might want a "Product" button on some of the line items as they are listed out in the UI.


So, perhaps I can take a shot at this (I think I understand what you’re saying). The case that comes to mind for me is a dropdown for selecting a line item’s list of possible “types” could be queried, but that is a lot of duplication in the response, since each line has the same list of options. If that’s the kind of thing you’re talking about, then I agree: don’t do it that way. There are numerous options (all assume you’re loading that alt list once): 1. Query for a top-level key that contains the list. E.g. [:dropdown-options/line-item-type '_] which could be a denormalized OR normalized list of maps. If normalized, of course you’d just a join in the query. 2. Use a post mutation to “join” in the already loaded list as a normalized to-many edge on each LineItem just after the load. 3. Make a system for demand-loading them as they’re needed. E.g. In this example perhaps the LineItem componentDidMount looks to see if the list is loaded, and loads and/or joins to it (with a conditional transact!) Lots of other combos/inventions you could do…there’s :shared-fn on the app, for example. I’ve done all of the above, depending on the situation @U0D5RN0S1


The products are already in app state. But the query of the defsc 'LineItem' includes a 'to one' join to the Product defsc (that's a 'lookup'). Using Fulcro as it is the tree of data coming back has duplicates, not surprisingly. But the duplication is not the issue. The issue is that 'fully fleshed out' products are being brought back at all. It would be sufficient that just {:db/id a-product-id} were coming back. I can make the server send back a response like that (`{:db/id a-product-id}`). I should try the post-mutation way you suggested. However the lookup merging could happen in a more automatic way, although I haven't thought that through. My understanding is that merge always says if it was queried and didn't come back then it has been deleted on the server and so should be on the client. In the case of {:db/id a-product-id} coming back I'm not sure that's the right thinking. To me the obvious thinking is well - that must be lookup data, I can look it up in app state, no need for a post mutation. To me a 'lookup' is always going from a many to a one. (And a 'master-detail' is from a one to a many). Any screen consists of nothing but master-detail and lookup relationships.


have you considered using :without in the load so it doesn’t touch that field?


and :pre-merge in defsc for that matter


Also: F3 or F2? The merge behavior is quite customizable in F3


So, for your specific example, I would make a new LineItemProduct class that queries for just the ID (and possible title I want to show, for convenience). Then the server won’t send back more than you’re asking for, the ident of that component can share the product ident, and the default merge behavior will keep the rest of product in tact.


(defsc LineItemProduct [_ _]
  {:query [:db/id :product/name]
   :ident [:product/id :db/id]  ; whatever your ident in Product is
  ;; render what it should look like in this context


If you don’t include the product name in this new component, then it won’t come from the server, but it won’t come in on props either. You option then is to add the product table to the query, and find it yourself by id at render time. OR, when you load you can say :without #{:product/name} and you should get back the id, the name should not be affected in the existing record (if it is, I’d consider it a bug), and your props will get it from the local db.


Fulcro Inspect is throwing some interesting errors:

[1091:775:1008/150655.488660:ERROR:CONSOLE(5133)] "Error patching state, no previous state available. -433118367", source:  (5133)


It happens when I interact with a particular component though, which I might have screwed up in some manner.


The console turns into a gaping hole of nothing, but the app keeps running normally in the window, weirdly enough.


@henrik This is a known issue that we haven’t been able to patch yet. The database view is kept updated via diffs (it’s a separate memory space in a dev tool, so we have to send db by messages, and sending the whole db is very slow). Sometimes something you do to state confuses that (perhaps a missed diff?). It really should re-sync, or at least have a re-sync button.


Gotcha. Browser plugin development is great, except for the “browser” bit (and possibly the “development” bit).


don’t forget the “plugin” bit 😜

Arto Kalishian19:10:52

I have reached 3.8 in the Fulcro documentation. Enjoying it so far. I have stumbled upon a line that made me curious (since I just recently learned CLJ / CLJS) is this even possible in any other programming language? 🙂 (comp/transact! this `[(ops/delete-person {:list-name "Friends" :person "Fred"})])


other programming languages typically encode such things in strings, or as complex custom bunches-o-types with builder patterns…e.g. Java:

MutationBuilder.newInstance().setOperation("delete-person").setParameters(new HashMap(...)).build();

👍 4

Lisps are nice in that the code is just data…so you can use it that way when you want.


js at least has literals for data structures (JSON), so you can get closer…though you still end up using things like strings because JSON is so paltry in terms of types


[ ["delete-person" {"list-name": "Friends" ...} ]]


I’ve toyed with trying to make a fulcro for some other lang, but having decent data literals for writing queries and mutations is one of the things that makes clj(s) pretty compelling for the task.

👍 4

You could use short function names:

M("delete-person", P("list-name", "Friends", "person", "Fred"))


and you could easily get the symbol-looking syntax just with static declarations:

public static Mutation delete-person = new Mutation("delete-person");


and then use delete-person in place of the string…


point is, it’s a lot of extra boilerplate to get back to the nicer notation, but it is possible.


But it is tempting to go down the rabbit hole…a Mutation class could integrate into the dispatch system, etc…

public static Mutation deletePerson = MutationBuilder.builder().setSymbol("the.namespace/delete-person").setAction((env) => ...).setRemote((env) => ...)


tx.transact("Frields", "Fred"), ...);

👍 4

but then I’d miss my structural editing, macros that my IDE can just treat like plain functions, simple js build sytem (thank you @thheller), immutable data, data literals, hot code reload that “just works”, to name a few 😜

❤️ 12

The trouble with using Pathom compared to changing the functionality of merging so that for example :line-item/product with a value of just a reference {:db/id 4654...} gets properly merged into app state is that, well, you've disconnected from app state. I might want a "Product" button on some of the line items as they are listed out in the UI.