Fork me on GitHub
#fulcro
<
2020-03-10
>
tony.kay03:03:30

RAD got a bit more dynamic today. There are now 3 ways to add dynamics to a form, as described here: http://book.fulcrologic.com/RAD.html#_dynamic_forms NOTE: This requires 3.1.20-SNAPSHOT of Fulcro, as I had to evolve form-state a bit to deal with validation of edges, which it did not yet support.

tony.kay03:03:34

👍 28
👀 4
😮 4
tony.kay03:03:15

All the dynamism shown there is driven by about 17 lines of code, and is pretty much described in the book.

otwieracz06:03:16

Hey, any ideas how should I use https://adazzle.github.io/react-data-grid/docs/quick-start in Fulcro? ["react-data-grid" :as ReactDataGrid])) seems to return object :

=>(goog/typeOf ReactDataGrid)
"object"

✅ 4
Jakub HolĂ˝ (HolyJak)07:03:21

What object, ie what keys does it have? Could it be the module object, i.e. {"default": ..., someFn: ..} ?

otwieracz07:03:14

It's just empty map.

Jakub HolĂ˝ (HolyJak)07:03:52

That is weird. Based on Table 1 under https://shadow-cljs.github.io/docs/UsersGuide.html#npm I guess you need ["react-data-grid" :default ReactDataGrid]

Jakub HolĂ˝ (HolyJak)07:03:21

So (js/Object.keys ReactDataGrid) returns nothing?

otwieracz07:03:36

Right now I can't even test it, beacause:

otwieracz07:03:12

Obviously I have gigabytes of RAM available..

otwieracz10:03:30

OKm :default seems to work :)

🎉 4
otwieracz06:03:02

Trying to use react-factory on top of it obviously causes react_devtools_backend.js:6 Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.

Jakub HolĂ˝ (HolyJak)10:03:35

@tony.kay If I route to a router in the initial state and the target does dr/route-deferrer then 1. the default (i.e. first) target is displayed, 2. after the :deferred-timeout of 20ms the body of the router (if present) is rendered and can show a "loading..." notification. Correct? I think that showing the default route for 20ms is meaningless and if the router has no active route currently it should jump directly to rendering its body, instead of waiting the 20ms. Thoughts?

Jakub HolĂ˝ (HolyJak)10:03:25

Question: I want my deferred component to handle the "Loading..." x data display itself so inside I do

:will-enter
(fn [app {:keys [id]}]
  (dr/route-deferred [:component/id :offboarding-pages]
       #(do
          (df/load! app [:offboarding/id id] OffboardingQuery
                    {:target [:global/offboarding], :marker :offboarding})
          (comp/transact! app [(dr/target-ready {:target [:component/id :offboarding-pages]})]))))
and in the body I check the marker for nil / loading? / failed? and display the content accordingly. However this does not work as I want. What is happening is that the target-ready is triggered as desired (though with a 100ms delay, which is little too long, but that is perhaps due to dev mode). Next it takes 1.7s between that and the component actually rendering the "loading..." indicator. Perhaps all this will be fast enough in prod mode. But I guess it is safer to just display the "loading..." indicator in the router body, perhaps with :always-render-body? true .... Detailed time log: 1. I force-reload the page 2. At 11:55:55.6 The router's (if (nil? current-state)) is displayed for a Âą4s 3. Tx log: 11:55:57.0 the router's UISM logs "begin" with :path-segment [] (perhaps due to dr/initialize! ?) 4. Tx log: 11:55:57.4 the router's logs begin with the actual path-segment (perhaps due to dr/change-route ?) 5. Tx log: 11:55:57.5 the load starts (and will take Âą3s) 6. Tx log: 11:55:57.6 target-ready is triggered 7. Network log: 11:55:58.0 the load request is sent, takes 3.1s 8. Tx log: 11:55:58.4 the router logs "ready!" 9. At 11:55:59.3 The component's (if (df/loading? marker)) is displayed 10. At 11:56:01.2 The component renders the data (I guess 1. - 4. are all a part of the initialization of the system (which I hope will be much faster in prod mode).) Comments?

tony.kay15:03:36

@holyjak I would agree with you that initial routing behavior could probably be tuned up a bit. The state machine is quite simple, so I’d expect those are easy fixes. In terms of your initial application load: I would think that fixing the initial behavior of the router’s state machine will help in some ways. Your timing of 1-4: What is going on between 2 and 3? I would not expect that delay to be anywhere near that long.

👀 4
Jakub HolĂ˝ (HolyJak)18:03:25

Hi Tony! I have tried to look into it but don't know where to look. The logs in Console do not have any timestamps and the Transactions tab starts with the UISM Begin log (step 3. above). So how do I found out more about what is happening between app/mount! and the UISM Begin log?

Jakub HolĂ˝ (HolyJak)20:03:48

BTW what do you think is an acceptable delay between the router logging a current-state = nil and its "UISM Begin" log? I have replaced the code with Âą the routing example from the book and the delay is now down to Âą 1.5s (was 2.4s in my original code). Is it still too much?

tony.kay20:03:33

You’re talking about the time between when the js is done loading, and when code should start running?

tony.kay20:03:41

should be super small…like a few ms

tony.kay20:03:54

initial render with be up to React’s overhead

tony.kay20:03:07

You could look at Chrome’s performance tab and see where CPU is being taken

Jakub HolĂ˝ (HolyJak)20:03:15

It is essentially time between calling app/mount!and the transaction log showing > State Machine (BEGIN):app.ui.tmp-people/TopRouter {:path-segment [], ...

Jakub HolĂ˝ (HolyJak)20:03:54

Sorry, I have to put my kid to bed now...

tony.kay20:03:21

it could just be React overhead, which I can do nothing aobut…initial render is just that

Jakub HolĂ˝ (HolyJak)20:03:43

Ok. I can try to track down the extra 1s my actual app spends there. Anything else that looks strange in the timeline posted above?

tony.kay15:03:50

from there, I can’t do anything about how long your network requests take 🙂

Jakub HolĂ˝ (HolyJak)15:03:00

I force to be 3s just to make sure I see it loading :)

👍 4
tony.kay15:03:16

but I’d be happy to help optimize anything that Fulcro’s doing that is causing that startup delay

otwieracz18:03:39

Hey, do you have any suggestions how to replicate behavior like that with Fulcro? https://adazzle.github.io/react-data-grid/docs/examples/cell-formatting

kszabo18:03:49

rendering specifics is orthogonal to Fulcro, it provides you the data for rendering the progress bar though

kszabo18:03:04

you can directly use the mentioned React components

otwieracz18:03:36

yes, but in this example I need to pass react component (formatter) to React Data Grid.

otwieracz18:03:26

I was looking at this before I asked, but it's hard to me to see how I can use it.

tony.kay19:03:45

@slawek098 if it is just a formatter you’re passing, can you just use a function? I mean, it really depends on if the component you’re passing needs access to Fulcro’s data model.

tony.kay19:03:10

But as far as React is concerned a function can behave as a component, right?

tony.kay19:03:21

I guess you’d still need a factory

otwieracz19:03:33

It does not seem to accept function.

tony.kay19:03:09

no no, a function is a valid class, but it may need a factory

otwieracz19:03:04

OK, let me try...

tony.kay19:03:54

the RDG docs say “pass a component”, which technically means a string, class extending Component, or a plain function. RDG does not say an element, so a regular function should work fine. Of course, props would be in (this-as this (.-props this)) I think

tony.kay19:03:23

you’re in pure js land here, so you have to understand cljs js interop

otwieracz19:03:12

(defn formatter [this]
  (str "foo" (.-value this)))

(def ui-formatter (comp/factory formatter))

(...)
           {:key id :name text :formatter (ui-formatter)})
(...)

otwieracz19:03:16

this seems to work

otwieracz19:03:27

but after changes to ui formatter it does not reload automatically

otwieracz19:03:35

I have to refresh the page to re-render it properly.

tony.kay19:03:56

definitely NOT comp/factory

tony.kay19:03:01

that factory is not for react interop

tony.kay19:03:47

just try {:name text :formatter (fn [] (this-as this (str "foo" (.. this -props -value))))}

tony.kay20:03:11

you calling a factory like that is actually generating an element, which is not what it calls for, and I would not expect it work work well

otwieracz20:03:35

Yes, I've got confused

otwieracz20:03:26

This does not seem to work

otwieracz20:03:02

But simple (fn [props] (str "foo: " (.-value props))) seems to do the trick

tony.kay20:03:48

technnically, within that function, you should be able to do (dom/div …)

otwieracz20:03:56

OK. So my (.-value) is map of props like: {:text-object/id #uuid "5e67ed05-d817-472c-9d65-e932ff5eff79", :text-object/text X motor control}

otwieracz20:03:18

Am I able to, from within this function, call factory of fulcro component?

otwieracz20:03:36

(defsc TextObject [this {:text-object/keys [id text]

tony.kay20:03:28

is that a stateful Fulcro component with a query/ident?

tony.kay20:03:46

or just a stateless one that you’ve written for this purpose?

tony.kay20:03:37

and when you say value is a map of props, is it a js-object or a real cljs map? If the answers are “not stateful” and “cljs map”, then (ui-text-object (.-value props)) should be fine, but don’t expect things like transact! to work in there.

tony.kay20:03:24

unless you use the HOC stuff referred to earlier…because that is the state you’re in: you’re letting something else render a fulcro component outside of the normal rendering…so Fulcro has no control or context unless you re-establish it

otwieracz20:03:28

OK, I think RDG makes no sense at this point

otwieracz20:03:44

If I want to render columns on my own..

tony.kay20:03:31

well, it can make sense…there is a lot it is doing for you if you need it. You just have to understand that as soon as you break into low-level js-land you have some glue to build.

otwieracz20:03:54

The problem I see is that in RDG formatter only changes the way data is presented.

otwieracz20:03:06

But when I start to edit it - it falls back to "original" value, unformatted.

tony.kay20:03:21

“edit it” = transact agaisnt Fulcro?

otwieracz20:03:38

Edit value in cell, what will transact mutation within fulcro.

tony.kay20:03:56

right, but RDG is what would call that?

otwieracz20:03:38

when I start to edit cell value in RDG it skips formatter.

otwieracz20:03:59

Imagine you've got formatter detecting URL of image and loading it into cell.

otwieracz20:03:08

When trying to edit cell, it will enable edition of the URL.

otwieracz20:03:20

Save it and it will load & display image back

otwieracz20:03:05

But in my case, if the data underneath the cell is whole map of properties for Fulcro component, then whole editing in RDG becomes broken.

otwieracz20:03:44

(defn formatter [props]
  (str (:text-object/text (.-value props))))

otwieracz20:03:08

that's how the cell is formatted

otwieracz20:03:11

but when I try to edit it:

otwieracz20:03:30

it immediately switches to "raw data"

otwieracz20:03:16

I need to think about it, what makes sense... Because from the other hand my data has to be text-editable.

sheluchin21:03:53

Is something like Storybook (https://storybook.js.org/) practical to use while developing Fulcro apps?

tony.kay21:03:21

See workspaces

sheluchin21:03:03

Is Workspaces something you guys recommend using as early as possible? I'm trying to keep the tooling thin as it's already a lot to learn. Is it worth adding it into the mix, or is it reasonable to hold off until I'm more familiar with some of the essential tooling?

tony.kay22:03:16

I’m pretty sure the template already includes it. very simple to get going with

✅ 4
sheluchin22:03:48

Ah, will have to check that out. Have not started a project using the template yet. Thanks for the heads up.