Reagent and data-oriented timing issues: How to act on conclusion of rendering the data?

Updating an old app, I am using raw reagent (not re-frame, as we do on our newer apps). My workflow is this:

  1. Generate a skeleton of a form that has been submitted

  2. Use API calls to download the data that fills that form

  3. Print the end result (I am enjoying using print.js, as per ClojureVerse recommendations)

    The flow works, as long as I have a button for specifically for printing once everything is downloaded. What I need, though, is to be able to print automatically as soon as the data is downloaded. I created a form3 Reagent type so I could get at lifecycle events but =:component-did-mount= fires too soon, before the DOM has loaded even my skeleton and printJS fails because the target DOM object doesn’t exist; and =:component-did-update= doesn’t fire on the first load (which is the only load that matters to me here). How can I get my reagent thing to print as soon as it finished rendering the data into the skeleton?

Wondering if you don’t need a hook into the reagent-render piece, dependent on some local state (a ratom), which is deref’d by the reagent-render function. Local ratom is updated after api calls are done and form is populated. reagent-render then renders the dom element and triggers the printjs thing (or even the button handler) as a side effect (unsure if side-effecting inside a render fn is verboten or not). I haven’t run into the case where the component methods weren’t enough to get the job done eventually though.

I would explore this if there is some isolated code to play with.

The trouble is that getting the data – and apparently even updating the component – is NOT the same as writing to the DOM, and so my raw javascript is not firing against the updated dom element. I’m to the point of maybe adding a sleep timer of a second or so, but that is a really dirty fix.

It’s hard to provide a minimal example since I would need to sanitize so much data. but the fact that I am using raw reagent atoms, with values like [:div @atom-value] (only, maybe three dozen of those) is generally the whole of it – how to browser-print the page automatically after those atom-value change are reflected on screen, that is proving the problem.

That’s my inclination though:

Getting the data → update some state → deref the state → render new dom node → during rendering, trigger or queue up a print.

I mean you can add watches to the ratoms too and queue up events in response as well (kind of hackish). Ideally you have the actual dom node that is about-to-be-rendered and queue up the printing at that point though.

I guess I’m a pretty unsophisticated Reagent user, but everything I do seems to extend to the virtual dom and NOT the visual dom. I’m not sure how to tease those two apart.

my demo seems to work.

I just hook into the component-did-update method and get automatic printing from printjs when the element changes in response to its app-state entry changing (which it derefs to render). I simulate delayed rendering with the api-call function and button (just a 500ms delay to async update the app-state).

Thanks for trying this out and sharing your code! That looks pretty similar to what I tried, minus the delay. A symptom I noticed is that on my crucial view, in which I have a list of items and clicking on one should fill out that skeleton and then print it (same page, just one skeleton element that changes as you click on different items from the list), print :on-component-did-update at first doesn’t work, and then it prints THE PREVIOUS state, not the new one that is even shown after you have clicked on one of them. So it is perpetually at a -1 on the print/display. I’m not sure your sample expresses this nuance (as I didn’t mention it): the skeleton is only loaded once, but the filler changes, and I want to print whenever that filler changes. Sorry not to have mentioned that detail. Maybe I’ve designed my system wrong, but that’s what I have.

depends on the dependencies and how the components are being refreshed and if the dependencies are flowing in a peculiar order. My example doesn’t suffer from that (in fact, update is invoked after mount and every time thereafter (which shows in the logged println console results)).

I have no idea what you are doing without a sample to look at though; maybe it’s a simple rewrite to rephrase the dataflow a bit so that changes are reacted to and printing is accomplished.

1 Like

I understand. I was hoping there was some simple “we got around this problem with…” answer, but I’m not sure how to provide a minimal example here; we are using internal API calls, external GraphQL calls, and some soon-to-be-released custom libraries for submitting and reviewing form submission, so there it’s tough to minimalize this securely. Thanks for all your help, though; I will try that async timeout your code demonstrates

The timeout has nothing substantive to do with the implementation; it’s just simulating an “API” call that is asynchronously delivering results (akin to user input or delayed network response) that update the app-state ratom, which triggers the component’s dependency in render, which triggers the component to update and render, which triggers printjs to print the result. I do not get previous-state issues you mentioned (just verified). I also did not inject any waiting or polling using delays; this is all flowing from the ratom dependencies and the react lifeycycle methods.

It seems like it would be trivial to mockup a small example that demos the skeleton logic and simulate the API call as I have done. That could get at the underlying principle/mismatch. Or not.