Fork me on GitHub
#fulcro
<
2020-02-27
>
Jakub Holý (HolyJak)16:02:45

Hi! How to troubleshoot when my component seems to get nil props yet the data is in the DB? In React I'd look at the component's and parent's props in the React dev tools but fulcro components have just something human incomprehensible there. Thanks! (I have discovered (-> (comp/get-indexes app.application/SPA) :class->components :app.ui.root/OffboardingPages first comp/props), which helps)

tony.kay21:02:09

It has to be query/ident/destructuring composition, or that the data isn’t linked in the db. There’s really nothing else.

Jakub Holý (HolyJak)21:02:46

See below, it's because props were nil. But the question is more about "troubleshooting best practices and tips".

tony.kay21:02:58

The latest version of Inspect (release in Electron, but delayed in Chrome store) has a db explorer that will allow you to click on idents and browse through normalized db as you would traverse it in UI…that is useful. Otherwise, looking in db from step to step and seeing where the break is. You’ve either got a break from lack of linkage (missing field with ident value on a join) or you’ve destructured it wrong in the code, which the defsc macro will usually warn you about.

❤️ 4
tony.kay21:02:30

I just visually walk up the code looking at the props destructure/query/ident/initiial-state (unless it was a loaded thing). If those match up on the tree, then it should just work. Never found a case where those were right and rendering didn’t happen.

tony.kay21:02:23

on loaded things, it’s possible you have a hosed :pre-merge, but more likely you forgot to use target to add the “edge” that gets to the loaded data in the view

tony.kay21:02:19

BTW: you can use the Inspect version early on chrome with just a few steps: 1. clone the inspect repo 2. npm install 3. npx shadow-cljs release chrome chrome-devtool

👍 4
tony.kay21:02:49

Then go to <about://extensions> in chrome, turn on developer mode, and Load Unpacked extension from the shells/chrome folder

tony.kay21:02:02

then close tab, and open new tab

Jakub Holý (HolyJak)22:02:04

Will try, thank you. The problem here was:

(defsc Information [this props offboarding]
  {:query [[df/marker-table :finalization]]
   :ident (fn [] [:component/id :information])} ...)
  
(def ui-information (comp/computed-factory Information))

(defsc BusinessInformationPage [this {:keys [info]} offboarding]
  {:query [{:info (comp/get-query Information)}]
   :ident (fn [] [:component/id :company])}
  (ui-information info offboarding))
It turns out that offboarding at the last line was ok but the infowas nil and thus neither was passed to Information, which surprised me. There is certainly a reason why info was nil (perhaps because there is currently no marker for :finalization ?) but as a beginner I fail to see the reason. If I was able to look at BusinessInformationPage and see that the offboarding is ok but the info prop is nil, then I could eventually find the problem more easily (which I eventually managed via get-indexes ... comp/props|comp/get-computed). Given my low level of knowledge and experience, just looking at the code doesn't reveal the problems because I cannot see them.

tony.kay01:02:19

you have no initial state. If there is no initial state, then there will be no graph of data for the initial view.

Jakub Holý (HolyJak)07:02:07

I have tried to add it but it has no effect, info is still nil:

(defsc BusinessInformationPage [this {:keys [info]} offboarding]
  {:query [{:info (comp/get-query Information)}]
   :ident (fn [] [:component/id :company])
   :initial-state {:info {}} ;; FIXME has no effect
   }
  (println "BusinessInformationPage info:" info)
  (ui-information info offboarding))
Why? update: Ok, changing to BusinessInformationPage .. :initial-state {:info {}} and Information :initial-state {} helped. I now see that I used the template form, which replaces the {}with the init. state of the subcomponent, which was nil.

4
tony.kay17:02:11

as I said: query/ident/initial-state. Then properly manage the graph over time with mutations. That’s all there is to it 🙂

Jakub Holý (HolyJak)17:02:37

Simple in theory, not so simple in practice, at least for me 🙂

tony.kay18:02:08

simple, but simple isn’t necessarily easy (at first), I think you mean. Once you see the pattern (from repetition) you’ll be surprised you ever had trouble.

Jakub Holý (HolyJak)19:02:10

A mystery: I have (def ui-information (comp/computed-factory Information)) and when I invoke it with

(ui-information
    nil ;{:fake-props? true}
    {:id "DUMMYID", :org "Fake Org A.S."})
then (-> (comp/get-indexes app.application/SPA) :class->components :app.ui.root/Information first comp/get-computed) returns nil But this gives the expected computed props if I pass non-nil props:
(ui-information
    {:fake-props? true}
    {:id "DUMMYID", :org "Fake Org A.S."})
Why?

tony.kay21:02:45

@holyjak so, Fulcro ferries props through reacts low-level js props. Fulcro props are in “fulcro$value” on the React props. Unfortunately react’s tools wont’ format that well, since it is a cljs map. Fulcro also supports ferrying props through js/React.setProps (which is how we do targeted rendering)…so any attempt to access props will look in the react props AND the react state and return the “newest” of the two.

tony.kay21:02:10

computed justs gets put on the props at a special key internally (or meta if it is a vector

Jakub Holý (HolyJak)21:02:53

And if props is nil it does not get set? Wouldn't it be reasonable, instead of "loosing" the computed props, to set them to {} if nil so that the computed props can be propagated? Or at least log a warning if there are computed props but props are nil?

tony.kay21:02:10

I guess technically that could be ok, though props should never be nil (i.e. you should not be rendering stateful components that have no representation in the db..you’ll get nil in idents and all sorts of madness). If it isn’t a stateful component, then it should not have a query, and then you don’t need computed, you should just use props

Jakub Holý (HolyJak)22:02:19

see the other thread where I posted the full example code. It is stateful and I don't understand why props is nil. Anyway it is confusing to get no warning in this case.

currentoor23:02:18

if you’re props are nil then that means there’s like an error

currentoor23:02:34

perhaps you haven’t setup up :initial-state correctly