Fork me on GitHub

Does anyone have strategies for dealing with large amounts of state / components in fulcro? I'm on my 2nd large active page, (4.5kloc) and it is becoming spaghetti again 😐.


I think the cause is me not fully matching how I code style I write in to how fulcro thinks. I end up with a bunch of crosstalk between elements, which is sub-optimal.


Hey! Can you give an example of that crosstalk?


I'll try 🙂. One e.g. is this pic. At the top you can pick a crop (Cotton here). Right below that input you can see some inputs that have the lbs label - lbs are the unit of cotton. That unit should also appear in Farm Stress Test under Low/High yield. Those are pretty distant parts of the app the way it's currently structured. I will say that the only viable idea I can think of is some type of interface file that defines all possible operations on the page, and allow that file to properly delegate all the possible user interactions. Not tried it yet, but I might if I can't come up with better ideas 🙂.


have you considered making the controls at top have a constant ident, and then querying for the controls in the other spots? From my perspective you have a tree that contains all this stuff. The shared values could be passed manually from top to bottom, but you can also say [{[:control :thing] […]}] in any component query and pull in the current values of the controls.


That introduces some coupling (children have to know ident of parent controls), which is where I’d tend to lean more in the direction of passing them down as computed.


hard to say more without really delving into your code


Yes-ish. I do that already to some extent. However, the particular issue here is the Low/High yield here must have data altered in the db. That unit flag is part of the data, so changing the crop must change the unit across the page in the db.


Has anyone figured out a way to make guardrails check the results of an async function? For example a function that returns a channel that will receive a string? Would be super cool if I could do

(>defn foo [] [=> (async string?)]
  (async/go "hello world!"))


Nope. It doesn’t return a string. It returns a channel, that happens to have a string on it.


If you put your “hello world!” code into a sync function, and the call that from foo, you’ll get the check where it belongs. For GR to check it your way, it would have to be pulling items off channels and shoving them back on, or some other mess. Possible, but not present.


(e.g. it could instrument the body and put a channel in-between your returned channel and what it actually returns)


yeah that last suggestion was what i was thinking...


messy indeed


but could work, and guardrails is pluggable


pluggable in what way?


I wrote the macro and don’t remember leaving this kind of pluggable 😄




Oh, I see. You mean do it as a wrapper…yeah, that’s perhaps a bit messy way of doing it


is there a cleaner way?


how else would i take the result from an async channel, validate it, then put it "back"


how is a wrapper going to work? Remember that macros eval opposite to function calls. Your wrapper would be applied to the “raw” output fn


not as an intermediate transform


I’ve not tried, so I don’t know for sure, but I suspect the only way to do it is to actually patch the >defn macro itself


i was thinking wrap the body in a go block, take the value from the body, run spec checks on it, return the value at the end of the go block


that only works if i can get a handle to the specs in my macro body


right…not sure they’re there. You can look/try 🙂


I’m open to a PR that makes this sort of thing possible, but since I’m also working on the Copilot stuff which uses this same macro it would have to not interfere with that


i just finished writing a bunch of async crap, next time i have to do this sort of thing, i might try a quick spike

Jakub Holý (HolyJak)09:01:35

You could wrap the returned channel in another and check as you move the data from the inner to the outer as proposed but you would perhaps also want to make sure that if the wrapper channel is closed, you close the inner one and vice versa. Not trivial to do everything right.


that channel wrapping is tricky, because you cant know the characteristics of the channel you are wrapping, how to follow buffer type/size? is the channel a promise channel?

😱 6

This is the kind of thing copilot could be taught to do (if I ever get it done). There’s some limited support a static checker like kondo could do as well. Either way this is probably more tractable with a source-level analysis than a runtime check. You could invent your own channel wrappers that do data flow checking instead.

Gleb Posobin07:01:59

The element picker in fulcro devtools doesn't work for me: I have added the com.fulcrologic.fulcro.inspect.dom-picker-preload preload, restarted shadow, but when I click pick element and click anywhere on the page nothing happens. Anything I should try?

Jakub Holý (HolyJak)08:01:48

Do you have latest versions of the tools and Fulcro? (I saw it working for other people so it is not broken)

Gleb Posobin14:01:24

Oh yes, that was it, thank you!

bananadance 3