Fork me on GitHub

Is there an idiomatic approach to using third party APIs. If wanted to use the Cognito JS lib for auth from the client, would the best (right) approach be to write a remote implementation as per


Depends on how the API works. A lot of auth APIs do redirects and such, and are intended to be embedded as-is and called from js. You could integrate a remote to talk to it, or you could call the methods of it directly.


you have merge-component and mutations you can call to interact with the app, so either direction is really ok.


You’re not the one doing to “talking”, so a remote may or may not make sense…an API that just wants you to give it callbacks are often best just used as designed, and pass them callbacks the trigger mutations via transact!


That last point makes sense.


I’m using a lib that wraps all the API stuff, and returns a promise. I’ll use it directly then trigger a mutation.


I’m working on a feature I’ve been wanting to add for roughly 3 years, but never get around to: batched networking. The idea is simple: When multiple loads are enqueued while you hold the thread, combine them into one network request. The implementation is a bit harder, because of numerous semantic guarantees that webapps want (and often don’t have), and that Fulcro provides. I’ve got an experimental version that I’ve released as 3.4.17-SNAPSHOT on clojars. DO NOT USE THIS VERSION IN PRODUCTION. It has debug logging messages, has not been well-tested, and defaults to allowing batch (which I want to make an option), I’m asking anyone that is interested in this feature to try this version out on their apps and let me know if it works. It will console.log a bunch of crap in js. Instructions: 1. You must be using handle-api-request from Fulcro on the server-side. The new handler understands how I’m combining requests. 2. I have not tried any extended http remote middleware. It should work, but beware. 3. Run some part of your app that issues a bunch of loads from a single thread of execution (e.g. startup that loads config, etc.) 4. Look at the normal Network tab in js dev tools. You should see those loads combined into one network request. 5. Look in Inspect. You should still see each load listed separately in the Network tab there. The times will be a little misleading, since they happened in parallel. You’ll see that each took a slight bit longer than the other (that’s the internal processing time diff). NOTE: Mutations are NOT batched. Only loads that are queued together while holding the thread, and which do NOT have an abort ID. Requests with abort IDs have to be sent by themselves or you cannot abort them alone 🙂

😻 13

I’ve tried it on a simple app so far, but have been working for about 13 hours…so I’m done for now.

😴 3

I ran this in a large production app, and it seems to be ok. I saw one potential issue, but I could never figure out if it was this change, or just a bug in the prod app. I’ll continue down the path of making this a thing you can enable, and hopefully get it on an official release soon.


Hi there. Is there a way to reset the app state? To elaborate, I want to reset the app state after logging out so it looks exactly like when the user opens the app for the first time. Thanks in advance.


This sounds highly domain-specific to me, and it's hard to give any advice beyond explaining how to manipulate data generally. 1. You can swap! on the state in a mutation action, and clear out whatever you want. But maybe you want to, 2. Load some fresh data from the server on log out, in which case the mutation could return that on remote.


Will try. Thanks 🙂

Jakub Holý (HolyJak)15:02:56

Yes. You can save a copy of the app state before your login mutation changes it and then restore it via swap! in the logout mutation.


Has anyone tried to plug some non-datomic datalog DB to Fulcro? Like Crux, Datalevin or Datahike?

Björn Ebbinghaus11:02:51

Are you talking about Fulcro RAD? Because Fulcro itself doesn't care about your backend very much.


yeah about fulcro RAD


No, but if you read the source of the datomic adapter, you’ll see that adapting to something like Crux is nearly trivial.

👍 3

Hi there again. I'm stumbling across some components not rendering like I want them to but not sure how or where I screwed up. So essentially I have a Main component

(defsc Main
  [this {:ui/keys [is-loading?] :as props}]
  {:ident         (fn [] [:component/id :main])
   :query         [:ui/is-loading?]
   :initial-state {:ui/is-loading? false}
   :route-segment ["main"]
   :will-enter    (fn [_ _] (route-immediate [:component/id :main]))}
  (let [app-state (current-state app)
        tab-query [{:session/current-user [{:user/tabs (comp/get-query Tab)}]}]
        user-tabs (db->tree tab-query app-state app-state)]
      (ui-tab-list (:session/current-user user-tabs)))))

(def ui-main (comp/factory Main))
and a TabList component
(defsc TabList
  [this {:keys [user/tabs ui/selected-tab]}]
  {:query         [:ui/selected-tab :user/tabs]
   :ident         (fn [] [:component/id :tab-list])}
  (let [tabs               (mapv #(assoc % :ui/selected (= (:tab/id %) selected-tab)) tabs)
        on-select-callback (fn [id])]
      (eui/ui-button {:onClick #(m/set-string! this :ui/selected-tab :value 2)} "Test")
      (eui/ui-button nil (or selected-tab "Hello"))))

(def ui-tab-list (comp/factory TabList))
But whenever I press the Test button it seems that the client db is updated with the new value 2 but the component still displays the old value. Would appreciate any insight. Thanks in advance 🙂

Jakub Holý (HolyJak)15:02:52

i.e. Main query should most certainly include (comp/get-query TabList) and TabList should query for what it needs. Equally, TabList should include the Tab query.


Thanks @U0522TWDA 🙂 I was beginning to suspect it has something to do with how I'm setting up and composing these components. Will give it another go now.


To add a bit more context: the reason why I went down this manual way is because I wanted to to query for :session/current-user (which sits at root) while Main sits at [:component/id :main]. As far as I know there is no other way to query for root-level stuff inside query block of a non-root component because it's relative rather than absolute. Perhaps I've made a fatal mistake and you can indeed do that?


That is quite life-changing! Or it's just me not reading things properly 😅 Either way thanks a lot 🙂

👍 3