fulcro

Book: http://book.fulcrologic.com, Community Resources: https://fulcro-community.github.io/, RAD book at http://book.fulcrologic.com/RAD.html
zilti 2020-12-19T00:16:02.165600Z

There's also cljfx for desktop apps, fyi. It implements a lot of React concepts on top of JavaFX

tony.kay 2020-12-19T00:27:22.168Z

@smith.adriane since the browser itself does focus and mutable inputs for you, React is a hack on top of that. So, to emulate it in a Fulcro-compatible way would mean you’d have to have a VDOM like thing, but then Fulcro is never really in control of focus…you cannot control that with React and state very easily at all.

tony.kay 2020-12-19T00:27:36.168400Z

so there won’t be an example of controlling a detail like focus

tony.kay 2020-12-19T00:27:53.168700Z

not to say you can’t do it, but it’s a lot of bookkeeping

tony.kay 2020-12-19T00:28:32.169600Z

And the js ecosystem has nice controls in React for form stuff…you could look at the F2 book…I think I had some samples in there…hold on

phronmophobic 2020-12-19T00:28:41.169800Z

right, I was trying to see if there was anything analagous available in fulcro. for example, re-frame has re-com

phronmophobic 2020-12-19T00:30:16.171600Z

it doesn't have to emulate a text input (which is unlikely since almost everyone except code mirror uses the built in input). anything that has state that is optionally controlled by the parent component would probably be good enough to get started.

phronmophobic 2020-12-19T00:33:23.173400Z

> to emulate it in a Fulcro-compatible way would mean you’d have to have a VDOM like thing I'm trying to avoid that. There's nothing special about state that describes text selection, cursors, or focus that, in principle, couldn't be handled just like the other state fulcro manages.

tony.kay 2020-12-19T00:35:09.174200Z

So, this old F2 code (which uses out-of-date syntax) would not be hard to port. I did not bring them forward to 3. https://github.com/fulcrologic/fulcro/blob/2.8.13/src/main/fulcro/ui/bootstrap3.cljc#L526

tony.kay 2020-12-19T00:35:46.174900Z

not sure what you’re looking for exactly

tony.kay 2020-12-19T00:36:39.175600Z

I got out of the business of making these kinds of things a long time ago, so not much in my OSS libs has it

tony.kay 2020-12-19T00:36:54.176200Z

except for RAD semantic ui plugin, but it’s a bit complex for an example to follow

phronmophobic 2020-12-19T00:37:51.177300Z

this is great! for example, it seems like the ::open? attribute could be completely managed by the dropdown component, but it could also be partially controlled by the parent component

✔️ 1
phronmophobic 2020-12-19T00:39:27.178100Z

I was also curious how to handle defaults for a generic component, which this also does https://github.com/fulcrologic/fulcro/blob/2.8.13/src/main/fulcro/ui/bootstrap3.cljc#L524

tony.kay 2020-12-19T00:39:47.178700Z

yeah, it would be very nice to have a lib of official Fulcro components, but the js ecosystem has so many that can be controlled, it’s (nearly) pointless waste to write them (for my time)

tony.kay 2020-12-19T00:40:28.179700Z

well, there’s more to it. You’re going to end up wanting multi-root renderer

tony.kay 2020-12-19T00:40:35.180Z

(probably)

tony.kay 2020-12-19T00:40:49.180600Z

otherwise you have to connect the state of components to the graph to initialize them (via mutations)

phronmophobic 2020-12-19T00:41:08.181100Z

in an ideal world (which doesn't exist), a lot of the state management would be more reusable across platforms and environments. not sure how far I'll get, but I enjoy working on it 🙂

tony.kay 2020-12-19T00:41:40.181400Z

there’s an example here of what that looks like: https://github.com/fulcrologic/fulcro/blob/develop/src/workspaces/com/fulcrologic/fulcro/cards/multi_root_cards.cljs#L25

tony.kay 2020-12-19T00:42:19.182300Z

the idea is that you can generate an id on the fly, put it in state, render in “disconnected” from the normal data graph, and even GC it when you unmount

phronmophobic 2020-12-19T00:47:14.182400Z

can't I just use default values if the data is missing (ie. uninitialized)?

tony.kay 2020-12-19T01:35:42.182700Z

remember that Fulcro is a View = F(state) library. The F in this case is a root pull of the database using the root query. If your data isn’t composed into that graph, you won’t get it

tony.kay 2020-12-19T01:36:40.182900Z

so, when you “spring” a component into existence you have to add it to that data graph. The initial set will already be there if you compose them via initial state, so yes, so for things that are truly a static and persistent part of your UI, you’re fine

tony.kay 2020-12-19T01:38:16.183200Z

When things get dynamic, you have to keep the graph in tact…so you might, for example, use merge-component! to merge a new instance of a control into state, and then join it somewhere in the graph (as shown in that video)

tony.kay 2020-12-19T01:38:57.183400Z

But in forms you’ll find you’d rather not complect the control with the data…in which case having stand-alone controlled components is very very useful

tony.kay 2020-12-19T01:40:08.183600Z

:user/profession "Programmer" doesn’t mix well with suddenly wanting to replace it with the graph of a UI control that hosts the data {:user/profession {:ui/open? true :options […] :value "Programmer"}}

tony.kay 2020-12-19T01:40:11.183800Z

the latter is a mess

tony.kay 2020-12-19T01:41:20.184Z

so then you could make something parallel: {:user/profession "Programmer" :user.profession/control {:ui/open? true …}} but then when you go to load some user (if you go there) you have to merge that control data with the raw data.

tony.kay 2020-12-19T01:41:42.184200Z

it’s why I mentioned floating roots. You’d rather have the controls data “spring to life” on demand, and go away when done.

tony.kay 2020-12-19T01:42:05.184400Z

I use semantic ui react for most UI, so I very very rarely actually write such controls.

tony.kay 2020-12-19T01:42:21.184600Z

but you’re getting into the business of writing that kind of this with what you’re doing, so…

phronmophobic 2020-12-19T03:11:39.185600Z

very cool. I’m looking forward to trying to apply all these ideas. Thanks again for your help!

genekim 2020-12-19T03:30:47.187Z

Good seeing you here, @smith.adriane — I love the work you did with membrane, and implementing re-frame over it via Skia: https://github.com/phronmophobic/membrane-re-frame-example. As well as your articles on revisiting UIs from first principles! https://blog.phronemophobic.com/what-is-a-user-interface.html

Gleb Posobin 2020-12-19T06:13:08.189400Z

When trying to add fulcro's transit middleware to my ring server, I get:

java.lang.RuntimeException: java.lang.Exception: Not supported: class org.eclipse.jetty.server.HttpInputOverHTTP
                     WriterFactory.java:65 com.cognitect.transit.impl.WriterFactory$1.write
                           transit.clj:171 cognitect.transit/write
                           transit.clj:168 cognitect.transit/write
                    api_middleware.clj:151 com.fulcrologic.fulcro.server.api-middleware/write
                    api_middleware.clj:148 com.fulcrologic.fulcro.server.api-middleware/write
                              AFn.java:160 clojure.lang.AFn.applyToHelper
                              AFn.java:144 clojure.lang.AFn.applyTo
                              core.clj:667 clojure.core/apply
                             core.clj:6185 clojure.core/update-in[fn]
                             core.clj:6186 clojure.core/update-in
                             core.clj:6172 clojure.core/update-in
                           RestFn.java:494 clojure.lang.RestFn.invoke
                    api_middleware.clj:169 com.fulcrologic.fulcro.server.api-middleware/wrap-transit-response[fn]
...
Am I doing something wrong? Is this issue described in pathom docs related to this: https://blog.wsscode.com/pathom/#_fixing_transit_encoding_issues? I am not sure how to apply that fix that they suggest.

Gleb Posobin 2020-12-19T06:27:10.190600Z

Ah, stupid mistake, wasn't parsing the request. Now back to the problems with parsing transit in the request...

Helins 2020-12-19T13:06:46.193700Z

I am learning more about the rendering internals and this puzzles me from the keyframe 2 renderer :

(if limited-refresh?
      (let [{limited-idents true} (group-by eql/ident? only-refresh)]
        (doseq [i limited-idents]
          (ior/render-components-with-ident! app i)))
      (kr/render! app options))))
It looks like it processes only components based on idents, not props like advertised in the book. Or am I missing/misunderstanding something?

Helins 2020-12-20T09:39:08.207900Z

@jatkin Thanks, I'll read more around that topic

Helins 2020-12-21T12:43:14.216Z

@jatkin So, what I don't understand is this: the bit from the keyframe-2 renderer code I posted in my first post grabs only idents from the :only-refresh option and discards anything else, including props, doesn't it?

JAtkins 2020-12-21T15:41:40.216400Z

Right? Not sure I follow the issue.

JAtkins 2020-12-21T15:51:44.216600Z

Keyframe renderer 2 has a different supported feature set. That is why the group-by function is there... :only-refresh can either take 1. Idents 2. Prop Keys I think either KR1 or Ident based renderer support refreshing based off of prop keys. However KR2 only has the feature set to refresh by Idents.

Helins 2020-12-21T16:14:18.216800Z

@jatkin So then I got confused by this passage in the book which clearly demonstrates that KR2 can refresh by prop keys whereas as you agree, the source clearly states otherwise: https://book.fulcrologic.com/#_using_keyframe_render_2

JAtkins 2020-12-21T16:34:48.217Z

oh, I'm a dumb dumb. It delagates everything to the original keyframe renderer, which does have support for prop keys

JAtkins 2020-12-21T16:46:09.217200Z

or... Hm. I've not dug this far into the rendering before. The ident renderer is the only AFAICT that supports prop keys refresh

tony.kay 2020-12-21T16:50:14.217400Z

Correct, ident optimized is the only one that bothers with prop refresh these days.

👍 1
JAtkins 2020-12-21T16:51:34.217600Z

cool. Book is slightly out of touch then. I can submit a PR if it's helpful. I'll read a bit more before I try to make the book canonical again 🙂

tony.kay 2020-12-21T16:52:32.217800Z

Only components with idents are refreshable without a root re-render anyway…and if you’re using any of these later renderers they default to render from root, so there is no longer a need to refresh by prop (which just looked up all the component idents whose queries had that prop and refreshed the nearest parent with an ident).

tony.kay 2020-12-21T16:52:59.218Z

The ident-optimized render used to be the default renderer…the book is probably just out of date with respect to that

tony.kay 2020-12-21T16:53:33.218200Z

@adam678 is there something in particular you’re trying to code, or just learning internals?

Helins 2020-12-21T16:56:41.218500Z

@tony.kay Learning internals and I was wondering how important it really was to use different kws just for optimization purposes. I don't really like exploding many keywords for the same thing (eg. making :person/name and :dog/name instead of just :<http://my.app/name|my.app/name`>).

Helins 2020-12-21T16:59:43.218800Z

Without prop refresh I understand that I don't have to worry about that and can use :<http://my.app/name|my.app/name> without being "un-idiomatic" but please correct me if I am forgetting about something else 🙂

tony.kay 2020-12-21T17:03:42.219Z

It is a very good idea to namespace your keywords to their domain, and making a generic “http://my.app/name”, while sometimes appropriate (a much better example would be :entity/owner, where you plan on pointing most entities at their owner), doing so as a “hygiene move” will cause you problems with other parts of your domain that have nothing to do with Fulcro. Remember that resolvers use these names for context, as can your code..having a mixed bag of overly generic stuff is like coding Jello…so don’t go overboard on making things generic: it will bite you.

tony.kay 2020-12-21T17:04:51.219200Z

As far as rendering optimizations went: prop refresh was a big hassle for people, led to a lot of confusion, and didn’t really actually help in real applications. The overhead if finding everything to refresh was often as bad as just rendering from root. So, I dropped the complexity.

Helins 2020-12-21T17:10:48.219400Z

Fair enough, thanks!

Jakub Holý 2020-12-19T15:38:58.193800Z

The if is the key I believe. You can supply it an option to ask for only a limited refresh I think. But it isn't the normal mode of operation.

👆 1
Helins 2020-12-19T18:30:05.194400Z

@tony.kay @holyjak I meant this example from the book:

(defsc SomeForm [this props]
  {:ident (fn [this props] [:component/id :form])
   :query [:some/prop]}
  (dom/input {:onChange (fn [evt] (comp/transact! this [(save ...)] {:only-refresh [:some/prop]}))}))
In a few words, what is supposed to ensure that components which query :some/prop will possibly re-render? What I understand is that that those are filtered out and not processed.

Gleb Posobin 2020-12-19T19:25:12.199600Z

I am trying to modify the fulcro template, and want to store the auth token in local storage, but can't understand how to do that. I understand that I have to add a remote, but I need to somehow parse the request in that remote? I just want to query one key in the local storage basically. The second question is how to save it: in the template there is a session component, it stores the username and whether the session is valid. I want to change the session state machine to load the auth token first, and then query the backend for the session details using this token. Do I need to make a new AuthToken component with a new query [:auth-token], add it as another actor to the state machine, and use uism/load with that actor?

Gleb Posobin 2020-12-19T19:58:12.201600Z

I guess a more concise version of the second question is: if I want to query data from a remote, do I have to have a component whose query corresponds to that data that I want?

Jakub Holý 2020-12-21T12:24:01.215800Z

Sounds as something worth a PR, perhaps to ignore the target and log a warning in such a case?

👆 1
Jakub Holý 2020-12-19T20:00:09.202800Z

Hello! I've published v0 of https://blog.jakubholy.net/2020/troubleshooting-fulcro/ Feedback & additions welcome. Source: https://github.com/holyjak/blog.jakubholy.net/blob/master/content/asc/posts/2020/troubleshooting-fulcro.asc

👍 5
genekim 2020-12-19T20:43:14.203500Z

Freaking awesome. So helpful!!!

❤️ 1
Gleb Posobin 2020-12-19T21:33:53.203800Z

This is what I did to read the token from local storage. Does this seem ok? The fact that I need to do eql/ast-&gt;query seems weird, isn't the query first specified as eql and then fulcro converts it to ast? How would I add mutations to this, so that I can write the auth token on login?