Fork me on GitHub

So, one of my goals (but not top priority) was to make it so that F3 could run (nearly?) headless. That you could manipulate an app via the APIs for some period of time before even mounting it on a DOM. Most of the APIs are not directly tied to React or really any kind of UI. During beta I’m going to be firming this up. @mss your problem may have been you were initializing or routing before mount. That would cause your error. In beta-11 I’m adding a :root-class parameter to app/fulcro-app so that you can tell Fulcro what your UI root is before mount! (which will still require the Root). Having the root class in advance makes a number of things work that cannot otherwise, such as routing before mount…a very desirable feature.


At the moment I’ve tested the following work: - dr/initialize! - dr/change-route - merge/merge-component! (initial state deep merges over what’s already in the state atom, so you could pre-merge things before mounting) - basic UI state machine operations I did have to also add an app/set-root! function so you could pre-set root without having circ refs on your app declaration.


Beta 11 is on Clojars.

parrot 20

I also pushed beta-12-SNAPSHOT, which includes initialize-state? options, so you can properly set up the app state while it is unmounted…this should lead to very easy headless state manipulation in CLJ for things like SSR and also some interesting testing possibilities…and whatever else we can dream up.

parrot 24

The startup of the template works perfectly in this headless mode (with dynamic routing and ui state machines that do remote loads), which is hopeful


that means full-stack general transaction processing is also working headless


I imagine one use would be triggering the actual mount! after some sequence of initialization steps, even from, say, a state machine.


This sort of gets rid of the need for :client-did-mount altogether…not that it was particularly useful in 3


realized that my issue: I didn’t implement :will-enter on my components and trigger a target-ready!. apologies for leading you on a bit of a wild goose chase :face_palm: :face_palm: :face_palm:


@mss no worries…that was all planned activity. In fact, I’m goign to make will-enter optional (since a lot of targets have a constant ident.)


I have a weird scenario where I’m doing a transact (on click) that calls df/load-action, the app-state is updating on every click but the UI is only updating on every other click. 1st, 3rd, 5th, etc..


(prim/transact! this `[(cancel-booking/fetch-quote-refund-change {:booking-id ~control-id :guest_refund_percentage ~guest_refund_percentage}) :cancel-booking])


(defmethod mutate 'cancel-booking/fetch-quote-refund-change [{:keys [state reconciler] :as env} _ {:keys [booking-id guest_refund_percentage]}]
  {:remote (df/remote-load env)
   :action (fn []
             (let [payload {:control-id booking-id
                            :params     {:admin_reason                    "quote"
                                         :custom_cancel_charge_multiplier (/ (- 100 guest_refund_percentage) 100)}}]
               (df/load-action env :cancellation-quote nil {:marker  false
                                                            :refresh [:cancel-booking]
                                                            :target  [:cancel-booking :tab :cancellation-quote]
                                                            :params  payload})))})


@njj hard to diagnose from description…you remembered remote-load in the remote section of the mutation?


yeah its odd for sure


I think there is a pattern of it updating every other time.. but other times it seems random


Fulcro 3 Beta 12 on Clojars.

- Added `app/initialize-state!` to set up state in headless mode.
- Added option to `set-root!` to support an `initialize-state?` option.
- Made `:will-enter` optional on route targets
- Added sanity checks in dynamic routing:
** Warn if will-enter returns an invalid ident
** Warn if will-enter fails to wrap ident in route-*
** Warn, on root mount, if any route targets have invalid route-segments

Should make debugging routing issues a bit easier.


the data is indeed coming back, I can console it from the render part of my component - but only sometimes does it actually update the UI :thinking_face:


@njj why not just use load! in the UI, instead of embedding it?looks like the UI knew everything already


I can give that a shot


making a wrapper function that takes the parameters and calls load (instead of involving a mutation) seems more appropriate. Might also solve your issue, but to be honest I doubt it has anything to do with the mutation/load layer


sounds like something messed up in your query/state

👍 4

@tony.kay Moving the load to the UI w/ df/load is much cleaner, same issue though. If I put the df/load twice in the onClick, it works every time :man-shrugging:


@njj probably a misunderstanding of how refresh works? I see you have a refresh key listed (:cancel-booking), so any component that queries for that will refresh after the load…is the stuff you’re looking for elsewhere? Also, if your component doesn’t query for data that is changing, then the props won’t change, and refresh will get short-circuited.


yeah, I updated the refresh to fs/form-config-join


which I may not even need


and yes, I’m querying the data that’s changing - I can even console before the first dom element and see the data coming in on each click but the UI only refreshes every other time


oddly enough, the things that don’t update are input fields - the other parts of the UI that are just dom/p for example that have that data do re-render


I can't understand why my component did update aren't called My component

:query [:file/id ...]
   :ident [:file/id :file/id]
   :componentDidUpdate (fn [_ _]
                         (prn [:componentDidUpdate (:file/id (fp/props this))]))}
  (prn [:render (:file/id (fp/props this))])
  (mol/text id))
on console:
[:render #fulcro/tempid["54490526-5505-44ab-962a-962a9c8819e1"]]
[:render #uuid "ca7c25de-fd29-45af-853b-4e8acf2de890"]


when I do a "hot reload", it trigger the didUpdate just after the render


I'm working inside a workspaces


@tony.kay Any idea why in my example input fields aren’t updating on first df/load, but static type dom elements are? If I make a dom/p with the same value as a dom/input, they will be one step behind each other


are you using the dom/inputs, or custom ones?


inputs are a bit of trouble in React in general…they are meant to be used with C.L. state, not async app state…so there are hacks you have to do to get them to “behave”


After some deep diving by the team, turns out making sure the value is a string matters


these are floats


so converted it to a string before making it the value, and boom it works


ah, yes, strings are what DOM uses


TIL, don’t use numbers for inputs haha