Fork me on GitHub
#fulcro
<
2020-01-31
>
thosmos04:01:02

Thank you for all you do! I signed up for a monthly donation. I wish I could do more.

🙏 4
Jakub HolĂ˝ (HolyJak)09:01:24

Hello! I have noticed that if I want to include a component in a router, I must give it a :query(even if empty) and initial state - if I leave out the former I get a "bad join" exception and if I leave out the latter I get a warning about a component being invoked with nil props. I believed I could use defsc without query/init.state but perhaps I misunderstood?

✅ 4
tony.kay16:01:33

Yes, dyn routers expect you to pass state through them, so the target must have a query and ident.

tony.kay16:01:12

It is technically possilble to make that not a requirement, but it currently isn’t written that way

👍 4
Jakub HolĂ˝ (HolyJak)09:01:39

Question: The Element tab in my Fulcro Inspect (1.0.17) is empty. DB etc. work. Is there a way to fix it? Thank you! (Chrome 79 on OSX)

tony.kay16:01:30

Not working for Fulcro 3…should probably be hidden.

mitchelkuijpers10:01:36

When trying to run fulcro-inspect in Linux I get:

A JavaScript error occurred in the main process
Uncaught Exception:
Error: Cannot find module 'electron-settings'
    at Module._resolveFilename (module.js:543:15)
    at Function.Module._resolveFilename (/opt/fulcro-inspect-electron/resources/electron.asar/common/reset-search-paths.js:35:12)
    at Function.Module._load (module.js:473:25)
    at Module.require (module.js:586:17)
    at require (internal/module.js:11:18)
    at /opt/fulcro-inspect-electron/resources/app.asar/js/background/main.js:2310:741
    at Object.<anonymous> (/opt/fulcro-inspect-electron/resources/app.asar/js/background/main.js:5454:3)
    at Object.<anonymous> (/opt/fulcro-inspect-electron/resources/app.asar/js/background/main.js:5456:3)
    at Module._compile (module.js:642:30)
    at Object.Module._extensions..js (module.js:653:10)

tony.kay16:01:17

not sure why that would be. That module is required for it on all platforms….but I do not test the linux build…you could try building it yourself..the DEVELOPMENT instructions tell you how..it’s easy

mitchelkuijpers16:01:56

I'll try that out then

tony.kay16:01:57

and if you’re on Linux you don’t need to use Docker 🙂

tony.kay16:01:08

just electron-builder build -l

tony.kay16:01:11

If it turns out to be a bad build I’ll delete the one from github and try rebuilding it some other time

mitchelkuijpers10:01:43

Anyone else has this problem?

Jakub HolĂ˝ (HolyJak)11:01:39

How do folks implement Error Boundaries in Fulcro? https://reactjs.org/docs/error-boundaries.html It is annoying to get an empty, white page due to a typo in a (external lib) prop name...

✅ 4
fjolne11:01:04

Fulcro components are just regular React components, you simply need to add :getDerivedStateFromError etc to the options map of defsc, look at its docstring for arguments.

❤️ 4
otwieracz11:01:33

Hey, I've got something I completely don't understand. Suddenly all my revolvers stopped working, every requests gets :com.wsscode.pathom.core/not-found response

otwieracz11:01:51

I don't see anything that even changed - do you have any clues how to debug Pathom resolving?

fjolne12:01:49

I’d suggest to switch to synchronous versions of parser, reader etc for debugging + add ::p/process-error to ::p/env with custom error logging

fjolne12:01:33

for the latter you also need p/error-handler-plugin included

otwieracz12:01:01

(defresolver wires-resolver [{:keys [datomic]} _input]
  {::pc/output [{:wires [:wire/id]}]}
  (let [wires (datomic/q '[:find (pull ?w [:wire/id])
                           :where [?w :wire/id]]
                         (datomic/db (:conn datomic)))]
    {:wires (map first wires)}))

(def resolvers [connector-resolver connectors-resolver terminal-resolver wire-resolver wires-resolver])

otwieracz12:01:21

(defn make-pathom-parser
  [datomic]
  (p/parser {::p/env     {::p/reader                 [p/map-reader
                                                      pc/reader2
                                                      pc/ident-reader
                                                      pc/index-reader]
                          ::pc/mutation-join-globals [:tempids]
                          :datomic                   datomic
                          }
             ::p/mutate  pc/mutate
             ::p/plugins [(pc/connect-plugin {::pc/register [resolvers/resolvers
                                                             mutations/mutations]})
                          p/error-handler-plugin]}))

otwieracz12:01:36

user=> 
((wires.parser/make-pathom-parser (:datomic system)) {} [{:wires [:wire/id]}])
{:wires :com.wsscode.pathom.core/not-found}

otwieracz12:01:46

I completely not understand why it is like so.

thosmos08:02:00

did you ever figure this out?

Jakub HolĂ˝ (HolyJak)12:01:53

Is there a way in Fulcro or shadow-cljs to show React errors nicely in the page instead of showing an empty page and having to read through the console log? (Without wrapping everything in an Error Boundary.) (E.g. if somewhere in a component I have (dom/div {{:dangerouslySetInnerHTML {:__html "Hi!" }} "I will cause a failure") ? Shadow-cljs shows nicely compile errors but not runtime React errors 😞

tony.kay16:01:43

There is not currently, nor do I have a strong interest to investigate it..console works fine for me 🙂 …if you have ideas, feel free to share them.

👍 4
Jakub HolĂ˝ (HolyJak)13:01:45

How does fulcro-garden-css work? Is it so that I need to add a :css [[:.myClass ..]] key with the CSS Garden style definition to the component, which will generate a CSS class with a unique name, which I can obtain via (let [{:keys [myClass]} (css/get-classnames MyComponent)] (div {:classes [myClass]})) ? Contrary, :css-global creates the class names as-given and thus there is no need for get-classnames , right? (I'd be happy to send a PR improving the docs, I just want to make sure first I actually understand it.) + I need to call (com.fulcrologic.fulcro-css.css-injection/upsert-css "componentcss" {:component root/Root}) on my root component and ensure that all components from the Root down have :css-include [ChildComponent1 ..]all the way down to the MyComponentthat I want to style with co-located styles. Correct?

tony.kay16:01:09

No, newer versions have an auto-scan. read the doc strings

tony.kay16:01:08

as long as components have queries and are linked together, the current version can scan for css at root

👀 4
tony.kay17:01:32

docs clearly mention auto-scan

tony.kay17:01:08

in more than one place

Jakub HolĂ˝ (HolyJak)17:01:05

Thank you. I will hopefully contribute some docs changes for idiots like me :)

Jakub HolĂ˝ (HolyJak)21:02:57

@U0CKQ19AQ I cannot get the autoscan to work (Fulcro 3.1.8, f-g-css 3.0.7) - I changed to :auto-include? true :

(cssi/upsert-css "componentcss" {:component root/Root, :auto-include? true})
and removed :css-include [Header] from my Root component. Hard reloading and the "componentcss" element is now empty. The Root and Header component are connected by queries so autoscan should work?!
Root :query [{:root/header (comp/get-query Header)} ...]
How do you troubleshoot these things? How can I verify that all my components have correct query and are properly linked together?

tony.kay02:02:14

(comp/get-query YourRoot) should show you the full query of the app (from a CLJS repl)

👍 4
tony.kay02:02:31

you can set source breakpoints in chroms

tony.kay02:02:49

you can set up deps to use the source of a local checkout of the libraries and add debug statements

Jakub HolĂ˝ (HolyJak)15:01:30

Q: According to http://book.fulcrologic.com/#_routing_targets I can leave out :route-segment for a singleton (";; optional: defaults the the component's ident (singletons only)") yet for this component:

(defsc Private [_ _]
  {:query         []
   :initial-state {}
   :ident (fn [] [:component/id :private])}
  (div (p "TODO")))
that looks like a singleton to me I am getting > ERROR [com.fulcrologic.fulcro.routing.dynamic-routing:535] - Route target app.ui.root/Private of router app.ui.root/BaseRouter does not declare a valid :route-segment. Route segments must be non-empty vector that contain only strings and keywords What am I doing wrong?

✅ 4
tony.kay16:01:13

the doc is wrong. The :will-enter defaults to that

👍 4
tony.kay16:01:36

route segment is always required…there is nothing to make up there…it is a vector of strings I cannot guess, nor does it make sense to

tony.kay16:01:42

actually the doc is right, it is just formatted poorly

tony.kay16:01:50

line comments go with the line BELOW them

tony.kay16:01:16

fixed

❤️ 4
Jakub HolĂ˝ (HolyJak)16:01:23

Last question of today: When I copy the code from http://book.fulcrologic.com/#_live_router_example but rename Root to RootNested and wrap it in a new Root, the navigation stops working and gets stuck at "Unknown route". Why? How to fix?

...
(defsc RootNested [this {:root/keys [router]}] ;; former Root
  {:query         [{:root/router (comp/get-query TopRouter)}]
   :initial-state {:root/router {}}}
  (dom/div
    (dom/button {:onClick #(dr/change-route this ["main"])} "Go to main")
    (dom/button {:onClick #(dr/change-route this ["settings"])} "Go to settings")
    (dom/button {:onClick #(dr/change-route this ["person" "1"])} "Go to person 1")
    (dom/button {:onClick #(dr/change-route this ["person" "2"])} "Go to person 2")
    (ui-top-router router)))

(def ui-root-nested (comp/factory RootNested))

(defsc Root [this {}] ;; added
  {:query         [{:root/nested (comp/get-query RootNested)}]
   :initial-state {:root/nested {}}}
  (ui-root-nested))

✅ 4
tony.kay17:01:09

you have to pass props through…you did an empty destructuring in root

tony.kay17:01:17

how is it supposed to work without data?

Jakub HolĂ˝ (HolyJak)17:01:08

I see, I misunderstood how query works. So I must pass the :root/nested props to the UI-nested-root...

Jakub HolĂ˝ (HolyJak)17:01:42

Thanks a lot! I am still only learning...

tony.kay17:01:42

yep…that’s really the main concept…idents tell Fulcro how to normalize a tree, and queries tell it how to pull data (as that tree) from servers and from the local normalized db…that’s really it. It’s always a tree in the UI, and always normalized in databases. You should always think about the UI as a tree from root (optimizations may jump around, but they rely on the first render to actually be from root)

tony.kay17:01:21

Since it is normalized in db, you can ask for any subtree from a server and tack it into place.

tony.kay17:01:40

but the overall tree from root is just that: a data tree from root…just happens to be stored in a normalized form.

Jakub HolĂ˝ (HolyJak)17:01:13

the problem was I was kind of thinking in terms of reagent subscriptions and not realizing that query is just info composed to root and the actual data must be propagated from root as in a normal react app.

tony.kay17:01:58

I understood that…common misconception. It actually would not be hard to make components that could “act” as their own roots and get what you had to work, but the composed queries actually come in handy for so much that it hasn’t been worth the trade-off….routers, for example, use the query to find each other.

👍 4
Jakub HolĂ˝ (HolyJak)17:01:30

Thank you for the helpful error messages such as > You are routing to a router :app.ui.root/BaseRouter whose state was not composed into the app from root. !

tony.kay17:01:12

I’m trying to make that the norm…still have places that could use improvement, but yeah…

Jakub HolĂ˝ (HolyJak)17:01:43

Hm, why do I get ☝️ ? Do I have to query router props in the root component?! I have

Root :query [{:root/content (comp/get-query Content)}]
     :initial-state {:root/header {}, :root/content {}}
  ;-> (ui-content (:root/content props))
  Content :query [{:root/router (comp/get-query BaseRouter)}]
          :initial-state {:root/router {}}
    ;-> (ui-base-router (:root/router props))
    BaseRouter

tony.kay17:01:14

no, it is a chain/tree

tony.kay17:01:29

does the target have initial state?

tony.kay17:01:50

you composed the queries, but that does not compose the state

Jakub HolĂ˝ (HolyJak)17:01:07

But I am passing the state down via props (see the ; -> (ui-.. lines?!

tony.kay17:01:27

but is the state in the database

Jakub HolĂ˝ (HolyJak)17:01:24

Every target component of the router has

:initial-state {}, :query []

tony.kay17:01:25

it really is nothing more than: you provide an initial tree of data that FUlcro normalizes into a database, then it uses the query to pull that state back into the ui

tony.kay17:01:45

subquery probably needs something…I’ve never tried that

tony.kay17:01:54

I can’t imagine a component that doesn’t need something.

Jakub HolĂ˝ (HolyJak)17:01:56

They are not flashed out yet, they will need something eventually (aside the first one which is just info panel)

tony.kay18:01:12

then give them a fake prop and query…`:x 1`

tony.kay18:01:24

I’m not sure that is a problem, but worth trying

Jakub HolĂ˝ (HolyJak)18:01:25

Hm, now it works suddenly. I did the suggested change then undid it yet it still works. Perhaps it just needed hard reload or something like that...

Jakub HolĂ˝ (HolyJak)18:01:23

Thank you, Tony! I learned a lot today!

felipethome20:01:52

Hi! Is there a guide to migrate from Fulcro 2 to 3?

Jakub HolĂ˝ (HolyJak)21:01:41

Regarding routing, how to make sure that the initial change-route happens before the application is shown? Currently I do 1. app/set-root! 2. dr/initialize! 3. dr/change-route (based on the current URL) 4. app/mount! But the app shows first with the default (first) route target and only after a while it switches to the route from 3. http://book.fulcrologic.com/#_initial_route doesn't help here...

tony.kay22:01:54

@holyjak so change route is a transaction, and transactions go into a queue that is processed soon after. You probably need to put the mount into a timer to allow things to settle down

👍 4
tony.kay22:01:20

I should probably formalize a mechanism for initialization that takes care of the timing

tony.kay22:01:04

the other option is to put a “ready?” flag in your state that hides UI, and then set it to true once you’re sure things are the way you want them

tony.kay22:01:18

but it’s all the same: js-land is async, so it’s a bit of a pain to do cleanly

Jakub HolĂ˝ (HolyJak)22:01:04

How do I know the transaction has been executed (and thus can mount)? What I do now is I rely on that transactions are executed sequentially and simply transact! a mutation that does (swap! state assoc :ui/routing-ready? true) and ask for it in my root component and render nil if false