Fork me on GitHub
#fulcro
<
2019-12-10
>
thosmos00:12:38

F3 (I’m migrating my F2 app to F3)

tony.kay00:12:33

ok, so derived data requires that you do either one of: 1. Use the keyframe renderer, and don’t worry about anything like this ever again. 2. Add a standard F2 follow-on read of a prop on the parent to the transact! that makes the change.

tony.kay00:12:16

There’s a 3rd option I’ve added recently that actually is a better alt in many (probably all) cases: <http://book.fulcrologic.com/#RenderingOptimizations>

tony.kay00:12:49

It does keyframe, but supports :only-refresh on transactions. This lets you do targeted refresh at component-local state speeds when you need it, but otherwise “just works”

mitchelkuijpers08:12:16

I love this approach, this is way simpler to learn to my colleagues

tony.kay00:12:35

I personally have come to prefer this last option, as it is a “forget it” until something is slow, then add a single option to a transact to speed it back up

tony.kay00:12:17

it will probably become the default when I have time to rewrite the portions of the book that matter…which means reading the whole book 😜

thosmos00:12:38

haha, ok yeah I just read about those earlier today, sounds like keyframe2 is the way to go

thosmos00:12:51

Ah yeah that works more like I was expecting …

Ahmed Hassan10:12:45

Where do we need Legacy UI Routers When we have Dynamic Router ?

tony.kay17:12:00

The union router has a lighter footprint in general than the new dynamic router, and a lot of older apps are still using it. It isn’t as full-featured, and probably should not be used for new apps. The old dynamic router has code splitting integrated into it, but is similarly limited, and it would not be that hard to just use the new dyn router and do your code loading in it. TL;DR: new apps never need the legacy ui routers.

✔️ 4
fjolne11:12:59

Hi there! I’m trying to figure out how to get ::fs/config normalized when I add it in :pre-merge:

(defsc SomeComponent [this props]
  {:query         [:some-field
                   fs/form-config-join]
   :form-fields   #{:some-field}
   :ident         (fn [] [:component/id :some-component])
   :pre-merge     (fn [{:keys [data-tree]}]
                    (fs/add-form-config SomeComponent data-tree))})
I’m merging the component via df/load!, which is apparently eliding ::fs/config from the query to send to remote, but I wonder why isn’t the original query used on the final merge (given that missing fields are already marked as ::not-found). The case: I want to add initial values to the incoming data-tree, and make them to look new when using fs/dirty-fields, but I don’t want to use tempid (and new-entity? would mark the whole entity, which is wrong in this case).

fjolne13:12:12

Eventually couldn’t find a better way than to init in a post-mutation, but that scales kinda bad for large forms with a lot of subforms. Anyway, much better than anything I worked with so far. I can’t really describe how much I’m in love with your work, @tony.kay!

tony.kay17:12:42

@UDQ2UEPMY there is a bug in F3 pre-merge…which is probably your problem…working on it. Thanks for the compliment.

tony.kay17:12:54

Also, the way to work around form complexity like this is to use UISM…See RAD’s approach, for example: https://github.com/fulcrologic/fulcro-rad/blob/develop/src/main/com/fulcrologic/rad/form.cljc#L247

tony.kay17:12:21

where the start edit or create functionality does the proper amount of marking complete and setting defaults (incomplete implementation, but coming along…)

tony.kay17:12:57

Then you’ve generalized ALL form logic to one bit of reusable code that isn’t as complected with the component that renders the form.

fjolne17:12:02

Cool, thanks, will check this out!

Robin Jakobsson12:12:43

How much does Fulcro weigh at baseline when gzipped, together with cljs? Is it around ~500kb?

thheller14:12:54

closer to about 200kb gzip'd

👍 16
mss17:12:09

within a component, can I expect calling set-value! on a second, imported component to work correctly? e.g. (fm/set-value! SomeOtherImportedComponent :field 123)

tony.kay17:12:52

No. Use the source.

geraldodev18:12:29

any known impediment of using react 16.10.x with fulcro ?

tony.kay19:12:53

none I know of

👍 4
DomenM19:12:35

Hi. I’m a total beginner with fulcro and I’m trying to get a websocket connection working both ways. I got com.fulcrologic/fulcro-websockets working on the client side:

(defonce APP (app/fulcro-app
               {:remotes {:remote (fws/fulcro-websocket-remote
                                    {:push-handler (fn [whatever] (println (str "WS EVENT! " whatever)))})}}))
and on the server side:
(def websockets
  (fws/start! (fws/make-websockets
                api-parser
                {:http-server-adapter (get-sch-adapter)
                 :sente-options       {:csrf-token-fn nil}})))

(def middleware
  (-> not-found-handler
      (fws/wrap-api websockets)
      (server/wrap-transit-params)
      (server/wrap-transit-response)
      wrap-keyword-params
      wrap-params
      (wrap-resource "public")
      wrap-content-type))
The application loads data correctly and the remote calls to mutations work as they should, but I’m entirely unable to get the :push-handler to be triggered from the server. I can call the handler from the cljs repl connected to the application and it works - prints out as expected, but anything I do with the (:send-fn websockets) function does nothing. Can someone please give me a pointer what I’m doing wrong?

tony.kay20:12:01

@nocnashada sente has a concept of client IDs

tony.kay20:12:14

you have to indicate which client(s) the send message should go to

tony.kay20:12:32

Assuming websockets is your “started” websockets:

(defn active-cids
  "Returns the active websocket client IDs in the given websockets handler. If a websockets handler
  is not supplied it defaults to the running server's gondola.component.websockets/websockets."
  ([]
   (active-cids websockets))
  ([ws-net]
   (-> ws-net :connected-uids deref :any set)))

(defn push-notification!
  "Send a message with verb :verb and payload :edn to all clients matching the :cids.  If ws-net is not
  supplied it defaults to the running gondola.component.websockets component."
  ([cids verb edn]
   (push-notification! websockets cids verb edn))
  ([ws-net cids verb edn]
   (let [clients   (active-cids ws-net)
         scids     (set cids)
         valid-ids (set/intersection clients scids)]
     (doseq [id valid-ids]
       (wsp/push websockets id verb edn)))))

tony.kay20:12:04

the :connected-uids is all connected clients

tony.kay20:12:33

the env of a mutation or resolve should include a client ID of the client (I think under key :cid) that talked to you (so if you want to do subscription registration, etc.)

tony.kay20:12:52

broadcast is just doing a push using all of the connected ids

tony.kay20:12:04

would love it if you want to update the docs…that got lost somewhere along the lines…used to be well-documented

DomenM20:12:37

(defn send-ws [uid] ((:send-fn app.server.server/websockets) uid [::asdf {:data "data"}]))
=> #'user/send-ws
(map send-ws (:ws @(:connected-uids app.server.server/websockets)))
=> (nil)
I’ve been doing this on the server REPL, hoping something would come through, but nothing does …

DomenM20:12:02

You mean got lost in the fulcro 2.7 -> 3.0?

tony.kay20:12:10

you also have to enable “parser-receives-env?” option

tony.kay20:12:29

if you want to see CID on the env, I think

tony.kay20:12:39

be careful using map…is lazy

tony.kay20:12:15

REPL eval probably saves you, but if you look I think you don’t have the data path quite right?

DomenM20:12:16

yeah, i know, but it should work when used in repl, right?

tony.kay20:12:35

connected-uids is an atom that contains :any

tony.kay20:12:57

I don’t remember the :ws key

DomenM20:12:12

i mean, i played around with creating the client ID watch (what’s it called …?) and it prints out client ids into the repl nicely

DomenM20:12:25

i’ll check the “parser-receives-env” thing

tony.kay20:12:38

the parser thing is just for mutations/resolvers

tony.kay20:12:40

not this REPL stuff

tony.kay20:12:21

I actively use the websockets support in two production projects. It works. The problem is almost certainly an understanding of how Sente figures out who you want to talk to

DomenM20:12:48

yeah, that’s what i figured 🙂

tony.kay20:12:01

the push function in the ws protocol is what I use

tony.kay20:12:08

as show in code above

DomenM20:12:46

Thanks for the help. I’ll go over this a bit more and check the code you pasted and I’ll see if I manage to get it working.

tony.kay20:12:08

it is defined as follows:

(defrecord Websockets [parser server-adapter server-options transit-handlers
                       ring-ajax-post ring-ajax-get-or-ws-handshake websockets-uri
                       ch-recv send-fn connected-uids stop-fn listeners
                       parser-accepts-env?]
  WSNet
  (add-listener [this listener]
    (log/info "Adding channel listener to websockets")
    (swap! listeners conj listener))
  (remove-listener [this listener]
    (log/info "Removing channel listener from websockets")
    (swap! listeners disj listener))
  (push [this cid verb edn]
    (send-fn cid [:api/server-push {:topic verb :msg edn}])))

DomenM20:12:55

listener, that’s the one.

tony.kay20:12:09

Note that the client expects the message be a :api/server-push

tony.kay20:12:34

you’re using send-fn directly, and inventing a diff one

DomenM20:12:09

yeah, i figured if i just throw everything into the function “it might work” …

DomenM20:12:06

It works! It’s just repl hacking, but that’s fine for now. Thanks @tony.kay

DomenM22:12:41

yup, this is it