fulcro

Book: http://book.fulcrologic.com, Community Resources: https://fulcro-community.github.io/, RAD book at http://book.fulcrologic.com/RAD.html
tony.kay 2021-02-22T06:29:40.023700Z

Uploading part 4 of Grokking Fulcro now. This episode dives into the internals of the humble comp/factory. This is some low-level detail that you might find interesting, or just obscure. Either way, you’re living in a React ecosystem, and seeing what hoops we’re jumping through to make that work is possibly useful to the more serious developer (or Fulcro contributor??? 😉 ).

Jakub Holý 2021-02-22T10:09:20.025300Z

Awesome! I am just at the first video but I have already benefited from and applied what I learned there. Thank you!

Casey 2021-02-22T12:24:59.025800Z

This series plus the original 24 part playlist are really stellar and great resources.

eckardjf 2021-02-22T21:26:35.049700Z

Really enjoying this series, looking forward to the next ones.

tony.kay 2021-02-23T05:11:56.051200Z

Good to hear. I personally like knowing how things work, so they’re fun to make from that point of view. A lot of the little minutiae are really mostly useful for super-advanced use-cases (e.g. I’ve never made a custom factory in any of my apps, but I could see the need to at some point….I honestly forgot about props middleware until I saw it while making the video yesterday, etc.).

tony.kay 2021-02-22T06:31:48.024500Z

It should be visible in the next 30 mins. YouTube is processing. Lower quality will be first, and the HD will show up sometime later.

👍 8
Casey 2021-02-22T12:26:25.027500Z

For components that only concern themselves with layout (some divs + css), is the convention to use a query'less defsc or just function?

tvaughan 2021-02-22T14:02:26.027600Z

I asked the same question, https://webcache.googleusercontent.com/search?q=cache:F1UQLUsATpUJ:https://clojurians-log.clojureverse.org/fulcro/2020-12-29+&cd=1&hl=es-419&ct=clnk&gl=cl > It’s all just function calls anyway. If there’s a common layout/formatting concern there is no problem at all putting that in a function, or even a component without query if you want shouldComponentUpdate optimizations.

tvaughan 2021-02-22T14:24:59.029100Z

Is it possible to mix ident and route-segment, something like:

:ident (fn [] [:foo/bar bar-id])
   :route-segment ["foo" :bar-id]
?

tvaughan 2021-02-23T11:50:05.053300Z

(defsc ShirtList
  [this {:keys [shirt-list/shirt-names]}]
  {:query [{:shirt-list/shirt-names (fcomps/get-query ShirtName)}]
   :ident (fn [] [:shirt-list/color shirt-color])
   :route-segment ["shirts" :shirt-color]
   :initial-state {:shirt-list/shirt-names []}
   :will-enter
   (fn [app {:keys [shirt-color]}]
     (dr/route-deferred [:shirt-list/color shirt-color]
       #(load! app :shirt-list/shirts ShirtName
          {:fallback `errors-mutations/check-response
           :params {:shirt/color (keyword "shirt.color" shirt-color)}
           :target [:shirt-list/color shirt-color :shirt-list/shirt-names]
           :post-mutation `dr/target-ready
           :post-mutation-params {:target [:shirt-list/color shirt-color]}})))}
  (dom/div
    (map #(ui-shirt-name %) shirt-names)))

tvaughan 2021-02-23T12:01:06.053500Z

Hey, I think I may have figured it out! Like you said, return a unique id in the pathom query. Took me a while to see how that would work :man-facepalming: The example component above is what I've been working with (incorrectly), but now I understand your earlier suggestion. Thanks!

🎉 1
tvaughan 2021-02-23T12:25:55.057400Z

I was confused because the component already knows about the shirt color because it's a part of the route params. It wasn't obvious to me that the solution was to have the resolver echo it back. I thought the component should just be able to make use of it

Jakub Holý 2021-02-23T12:38:01.057600Z

Right. The code above looks fine - you get the color from the route params and use it for the target-ready and to store the data in the right place of the client db. But as you point out, the data stored also need to include the color so either the resolver has to "echo it back" or you need :pre-merge or some post-mutation/action to add it in. (Though perhaps pre-merge cannot "see" it...)

Jakub Holý 2021-02-23T12:38:30.057800Z

If you can think of any way to make the documentation clearer on this point, please suggest it!

👍 1
Jakub Holý 2021-02-23T12:40:22.058100Z

> I was confused because the component already knows about the shirt color Yes, the component inside will-enter "knows" it but we also still need to make sure that it will be included in its props because ID always needs to be there. And Fulcro will not magically add it for you even though it could, in theory.

tvaughan 2021-02-23T12:47:42.058400Z

Thanks again for your help @holyjak

Jakub Holý 2021-02-23T12:53:20.058600Z

my pleasure 🙂 FYI I to those interested enough, I offer pair-programming help. The first hour is free without any obligation to continue after that. So if you run into some hairy issues, you can consider that 🙂

tvaughan 2021-02-23T12:59:41.058800Z

Awesome! I will definitely keep that in mind

Chicão 2021-02-22T14:38:13.032400Z

Hi, I'm starting in fulcro3 and I wanted to create routing in my app, I made a quick search and see something as state-machine, right? may you guys have some links that can help understand how is the best way to do this?

tvaughan 2021-02-22T14:53:28.032500Z

FYI, I'm not sure yet that bar-id will be a part of the component's props or query. It's passed to a child component currently

Jakub Holý 2021-02-22T16:13:09.033400Z

A teaser: I am creating a small library fulcro-troubleshooting to help detect problems earlier and find root causes faster. Stay tuned... (I should have mentioned that design help would be appreciated 😅)

🎉 2
Jakub Holý 2021-02-22T16:13:59.033700Z

Up to you. Defsc makes it more structured which is good for the React dev tools Components view and error messages.

Jakub Holý 2021-02-22T16:15:02.033900Z

the code is perfectly valid. But the keyword is I think arbitrary, it does not need to match the id prop. It just means "this is placeholder"

Jakub Holý 2021-02-22T16:15:35.034100Z

look at Dynamic Routing in the fulcro book

Chicão 2021-02-22T16:16:55.034300Z

ok , thanks

Jakub Holý 2021-02-22T16:22:13.034500Z

How familiar are you with Fulcro? If quite new then I'd really recommend following https://github.com/fulcro-community/guides/blob/main/learning-fulcro.adoc#tip-1-keep-it-simple for now

Chicão 2021-02-22T16:23:40.035Z

I'm starting with fulcro, usually I used reframe.

Jakub Holý 2021-02-22T16:24:02.035200Z

Then I would certainly wait.

Chicão 2021-02-22T16:25:23.035700Z

I haven't read it, I start with yotube videos and fulcro book

Jakub Holý 2021-02-22T16:26:13.036100Z

I strongly suggest you do. Though I am obviously biased as the main author 🙂

Chicão 2021-02-22T16:26:45.036300Z

I'll read it, thanks very much for recommendations

👍 2
hadils 2021-02-22T18:05:20.040100Z

Ok. I'm stumped. I've been working on this for 3 days now. I need help. Here's my UI tree (React Native):

(defsc Category [this {:category/keys [id label] :as props}]
  {:ident (fn [] [:category/id id])
   :query [:category/id :category/label]}
  (ui-view {:marginTop 50}
    (ui-text {:style {:fontSize 20}} (str id " " label))))

(def ui-category (comp/factory Category {:keyfn :category/id}))

(defsc CategoryList [this {:list/keys [id categories]}]
  {:ident (fn [] {:list/id id})
   :query [:list/id {:list/categories (comp/get-query Category)}]}
  (ui-view {}
    (ui-text {:style {:fontSize 32}} "CategoryList")
    (when categories
      (map ui-category categories))))

(def ui-category-list (comp/factory CategoryList))

(defsc Root [this {:keys [categories] :as props}]
  {:query         [{:categories (comp/get-query CategoryList)}]
   :initial-state {:categories {}}}
  (ui-view {:style {:marginTop 100}}
    (ui-text {:style {:fontWeight "bold" :fontSize 32}} "Root")
    (ui-category-list categories)))
and here are my resolvers:
#?(:clj
   (pc/defresolver categories-resolver [env {:list/keys [id]}]
     {::pc/input  #{:list/id}
      ::pc/output [{:list/categories [:category/id]}]}
     {:list/categories (queries/get-all-categories env nil)}))

#?(:clj
   (pc/defresolver list-id-resolver [env _]
     {::pc/output [{:categories [:list/id]}]}
     {:categories {:list/id :categories}}))
with id and label defined as per the Fulcro RAD demo. I don't know why this does not render the individual categories.

Jakub Holý 2021-02-23T21:13:45.063400Z

@hadilsabbagh18 https://clojurians.slack.com/archives/C68M60S4F/p1614110142063000 would have showed you the ident mistake. Though I guess I need to replace dom/div and p with something else for native... Any suggestions?

hadils 2021-02-23T21:15:42.063700Z

Hi @holyjak. I am not thrown off by regular React. My biggest problems seem to be grokking the root component of my UI tree. I just don't know how to connect it to my load!

hadils 2021-02-23T21:17:02.063900Z

I just missed it into your Fulcro Troubleshooting Decision Tree, that's all. I've been reading carefully.

👍 1
Jakub Holý 2021-02-24T09:35:50.070400Z

> My biggest problems seem to be grokking the root component of my UI tree. I just don't know how to connect it to my load! Could you elaborate? Your load! as shown above, with the data coming back, seems correct, no? So is normalization of the (correct) data into the client DB not doing what you expected?

tvaughan 2021-02-22T18:09:13.040200Z

That's the problem though, bar-id does not exist in the component's props. I want different instances of the component in Fulcro's db indexed by a dynamic route param

tony.kay 2021-02-22T19:00:56.040600Z

where is the load?

tony.kay 2021-02-22T19:01:47.040800Z

I expect to see a (df/load! app :categories CategoryList)

hadils 2021-02-22T19:03:24.041Z

That is what I have.

hadils 2021-02-22T19:04:11.041200Z

(df/load! @SPA :categories root/CategoryList)

tony.kay 2021-02-22T19:04:46.041400Z

SPA should not need to be an atom, but that is ok…and in Inspect, so you see the load work and return the right thing?

hadils 2021-02-22T19:06:11.041600Z

Here is the screenshot of Fulcro Inspect. :list/id looks wrong to me...

hadils 2021-02-22T19:06:38.042Z

The nli key bothers me.

tony.kay 2021-02-22T19:06:53.042200Z

that is not what I asked

tony.kay 2021-02-22T19:06:58.042400Z

please read the question carefully

tony.kay 2021-02-22T19:07:12.042600Z

In the network tab, what do you see?

hadils 2021-02-22T19:07:13.042800Z

No the load does not return the right thing.

Jakub Holý 2021-02-22T19:07:17.043Z

That doesn't have anything to do with the segment I think. Look at deferred routing - it can see route params and mark a particular ident as ready for display

hadils 2021-02-22T19:07:20.043200Z

Oh, sorry.

tony.kay 2021-02-22T19:07:33.043400Z

please show

hadils 2021-02-22T19:07:59.043600Z

RequestSend to query
[{:categories
  [:list/id {:list/categories [:category/id :category/label]}]}]
Response
{:categories
 {:list/id :categories,
  :list/categories
  [{:category/id #uuid "ffffffff-ffff-ffff-ffff-000000001000",
    :category/label "Landscaping"}
   {:category/id #uuid "ffffffff-ffff-ffff-ffff-000000001003",
    :category/label "Winter"}
   {:category/id #uuid "ffffffff-ffff-ffff-ffff-000000001002",
    :category/label "Fall"}
   {:category/id #uuid "ffffffff-ffff-ffff-ffff-000000001001",
    :category/label "Spring/Summer"}]}}
Sorry

hadils 2021-02-22T19:08:50.043800Z

I didn't look there, so there's something wrong with my rendering, correct?

tony.kay 2021-02-22T19:08:51.044Z

no worries…but that looks fine, so not a problem with network API

tony.kay 2021-02-22T19:09:19.044200Z

what is all-categoeies?

tony.kay 2021-02-22T19:09:33.044400Z

and why is it in state?

tony.kay 2021-02-22T19:10:05.044600Z

nothing in your code mentions it, yet it is in your DB screen shot

tony.kay 2021-02-22T19:10:47.044800Z

which means something isn’t right in terms of what you’re showing me.

tony.kay 2021-02-22T19:11:35.045Z

OH….your ident function is totally hosed

tony.kay 2021-02-22T19:11:48.045200Z

:ident (fn [] {:list/id id})

Jakub Holý 2021-02-22T19:11:49.045400Z

The component obviously needs a unique prop for you to be able to distinguish the different instances, no?

tony.kay 2021-02-22T19:11:50.045600Z

is wrong

tony.kay 2021-02-22T19:11:54.045800Z

idents are vectors

hadils 2021-02-22T19:12:13.046Z

Ok. Thanks for your help.

tony.kay 2021-02-22T19:12:21.046200Z

Use either :ident :list/id (which will write it correctly FOR you), or (fn [] [:list/id id])

tony.kay 2021-02-22T19:12:47.046400Z

I still don’t understand why you have all-categories in state map, but that is the source of your mis-normalized data

hadils 2021-02-22T19:14:12.046600Z

Ok, that fixed it! Thanks Tony.

all-categories
Is an attribute which I used previously. I will try to restart and then remove it if it's still there...

hadils 2021-02-22T19:16:24.046800Z

It's still there. I will work on that. Thank you again.

Jakub Holý 2021-02-22T19:21:09.047Z

See the example here https://book.fulcrologic.com/#_deferred_routing

tvaughan 2021-02-22T19:29:12.047200Z

> The component obviously needs a unique prop for you to be able to distinguish the different instances, no? Right, so I would have to set this prop using the route param, somehow. Like a computed prop, maybe? This isn't something I can query for. I've played around with this a bit and I don't think it's possible. I'll have to think of a different approach. Thanks

Jakub Holý 2021-02-22T19:47:16.048Z

🙏 I am looking for beta-testers for https://github.com/holyjak/fulcro-troubleshooting Please try it out and let me know how it works! 🙏

2021-02-22T19:48:54.048200Z

I’m in! 😄

❤️ 1
Jakub Holý 2021-02-22T20:55:55.048900Z

Much appreciated!

Jakub Holý 2021-02-22T20:57:01.049100Z

Maybe if u explained more your use case? U want unique instances but they don't have unique data?!

markaddleman 2021-02-22T21:00:20.049400Z

I'm pretty new to guardrails so I'm not sure if handling fspecs correctly. I expect both of these functions to be valid. Instead, the guardrails-f results in a somewhat weird explanation.

tvaughan 2021-02-22T21:53:08.049900Z

Let's say I have a "shirts" component with a route segment like ["shirts" :color]. The value of :color is a param, e.g. a where clause, to a pathom query. The shirts component will have a collection of shirts which will be unique per shirt color, but it doesn't have its own id. I don't think it should be a singleton. Of course, I could be missing an obvious pattern here, but I can't think of an appropriate ident for the component other than the value of its route segment. Does this make sense? Thanks a lot for helping me work through this

Jakub Holý 2021-02-22T21:56:50.050100Z

Each unique thing needs a unique ID, I believe. If it doesn't, make one up, eg in your pathom resolver. Cannot color be the ID?

Jakub Holý 2021-02-22T21:58:51.050300Z

BTW https://blog.jakubholy.net/2020/troubleshooting-fulcro/ could have perhaps helped

tvaughan 2021-02-22T22:39:08.050600Z

That's what I was hoping for. However, this :ident (fn [] [:shirts (-> this dr/current-route second)]) doesn't seem to work properly. The component doesn't seem to respond correctly to route changes.