This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-04-18
Channels
- # announcements (1)
- # aws (13)
- # beginners (55)
- # calva (8)
- # cider (73)
- # cljs-dev (96)
- # clojure (119)
- # clojure-europe (4)
- # clojure-italy (41)
- # clojure-nl (14)
- # clojure-uk (6)
- # clojurescript (90)
- # cursive (14)
- # data-science (1)
- # datomic (20)
- # dirac (1)
- # emacs (32)
- # figwheel-main (11)
- # fulcro (81)
- # hoplon (2)
- # jobs (1)
- # lein-figwheel (2)
- # luminus (1)
- # lumo (19)
- # nyc (3)
- # off-topic (60)
- # other-languages (1)
- # pedestal (5)
- # quil (1)
- # re-frame (3)
- # reagent (3)
- # reitit (5)
- # remote-jobs (1)
- # ring-swagger (2)
- # shadow-cljs (43)
- # sql (15)
- # tools-deps (20)
- # vim (21)
- # yada (6)
How does fulcro solve the issue of queries like [{:join/pointless [{:join/pointless []]]
where joins are just there in order for the query to match the UI hierarchy?
can you give a example of a use-case UI ? Never really had to do this apart from when sending to the server, there I just added a wrapper component just for server interaction to get the shape I wanted and then a post-mutation to merge things back to the ui.
I think this is what placeholders solve: https://wilkerlucio.github.io/pathom/#_placeholders
Yes @thenonameguy exactly. In om.next that's exactly what I do, give these keys a special namespace and then in call the parser recursively if I meet those keys.
The problem is that they also get sent to the server, unless I separate my read query from my load query (which might be what fulcro does?)
The problem I see with doing that is that I lose the (perhaps only theoretical) benefit of not caring where my data comes from.
It just all seems a bit dirty.
I’ve not yet used this feature, so can’t comment on the dirty/clean part. To me, it seems okay for a graph resolver to accept that the client wants a certain structure and adding a feature like above to support it. If you want your UI tree to match your data tree I think this is unavoidable
This is a pathom feature though. Does that mean that it's the same in fulcro as in om.next? You'll end up sending these placeholders in the load queries and need something like pathom to deal with them server side? I then wonder how fulcro deals with the subsequent merge? Presumably these keys also need to be in the server response to match the initial query, for any normalization to take place.
In fulcro you can specify to elide certain keys from the server query, or even reformat what is being sent to the backend. The response from the server, if it does not match you can do the merging yourself using the post-mutation
I've done similar in om next, passing post mutations as params to a query. As I said above, it feels like you lose the benefit of not caring where the data comes from. You have a UI query and a load query that are different (one matching UI structure and one matching a more natural/backend structure).
Also, is it not the case that the app is no longer aware of one query that can hydrate it with all it's data?
Been wondering about this for a while. Is not knowing/caring about where the data comes from really a benefit ? Maybe I'm just used to it, but having just the app-state and tools like fulcro-inspect
makes things really easy to reason about/predict perf issues etc..
for the hydrate all it's data I usually rely on the router
stuff, as if I just navigated to that route.
I've found it to be a benefit, because when you come to rewrite a backend, or split into microservices, you often do that incrementally (https://www.martinfowler.com/bliki/StranglerApplication.html). In om.next, I've been able to just change certain parser reads to point to another backend. I have to admit, I'm still familiarizing myself with fulcro and it's not yet clear to me whether loads have to be to a server, or how i specify said server for said loads.
Perhaps the fulcro approach would be to do this routing on the backend using something like pathom
http://book.fulcrologic.com/#_fulcro_and_graphql When you create the client you can specify the :networking
. The default is named :remote
. For example you can have :rest-api
, :remote
, :graphql
. In the mutation or load you just specify 1 or multiple remotes.
or at least that's one way 😄 Been using fulcro for a while and constantly find it has a good story & support for about everything. The strangest thing though is the flexibility you have in your approach for all that it offers.
When do loads usually take place? Is there a good story for loading everything the app requires in a single request?
This is the kind of holistic overview i miss when using something like re-frame, which for all other intents and purposes i find pretty simple to reason about and get stuff done with.
You get to decide where the load happens. You can put it along side the route change for example http://book.fulcrologic.com/#_combining_routing_with_data_management . For the 1 single request, unless you specify :parallel true
in the load, fulcro has a small delay and will try to put the load-requests in a single api call (from the same remote). Ex: issuing (df/load :x) (df/load :y)
will be 1 single request in most cases.
I see, pretty cool
right, that last one: In Om Next the parser in involved with your loads…in Fulcro load is an operation that is triggered with what you want to load from where (so you can name the remote and component)…no rewriting roots, etc. Mutation joins are also integrated so that when you write a defmutation
the mutation itself can indicate the remote(s) (as in Om Next) but they can also indicate what component is being returned and where to target that in the graph.
As far as “senseless joins” go : In Fulcro 2 you just implement those by throwing an indent pointer of that name into state. A solution that initial state does for you automatically in many cases. In Fulcro 3 I’m considering letting components act as data roots (via stable idents). In practice doing the explicit “link” in state is so simple that it really isn’t a problem.
I'm not sure I understand the ident pointer idea. Do you have a simple example?
so that a join on whatever compnent uses table 1 can have [{:join-key …}]
just “follow the link”….via db->tree
In Om.next i've never really been sure how to deal with this.
I’ve been hitting multiple times the following situation: I am updating state in a component that has an input. The input receives a value from fulcro state but does not update. If I place this value in a span next to it, the span updates the value immediately once the mutation fires. however the fulcro input changes every two mutations.
I am changing state from somewhere else in the UI, not directly with the input onChange
event
Why would the span update though?
the span is next to the input, and the span updates its value, not the input
(defn ui-component [{:keys [prop prop2]}]
(println "renders")
(dom/div
(dom/span prop)
(dom/input {:value prop})
(dom/input {:value prop2 :onChange on-change})))
on-change
will mutate such that prop
changes, the span shows the different value but the input
stays the same @thenonameguy
the print statement also fires, so the functional component does re-render
looks like a bug on the dom/input
I’m thinking that this might be caused because of an uncontrolled input: http://book.fulcrologic.com/#_controlled_inputs
I’m not getting those warnings in the console though
the span
shows the right state
the input
does not
Not familiar with how fulcro uses react under the hood
For inputs https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/client/dom.cljs#L119
yeah @U3LP7DWPR not sure how that is using the :value
prop of the input to update the value in an input
Havent had any issues with inputs so far. seems a bit strange. Just for testing does it still behave the same if you change it to a defsc ?
My inputs work fine until I need to propagate a change on a value to another input from another
FYI, Just changing to defsc on it’s own won’t affect re-rendering. But adding an ident to that defsc component will, so that might be something to try.
@pvillegas12 The inputs do a workaround for async updates…you can use raw react inputs by writing a function that is essentially (js/React.createElement "input" (clj->js props))
not sure why you’re seeing that…we’ve been using inputs for years now without a reported issue
Let me try that @tony.kay
interesting @tony.kay, before I had something like this
(prim/transact! invoice-component
[(change-retention
{:invoice-component invoice-component
:ui-key (if (= category specs/ret-ica) :ui/retica :ui/retiva)
:category category
:rate rate})]))
which changed the value in the change-retention
mutation.
Changing to
(prim/transact! invoice-component
[(mut/set-value {:component invoice-component :field field :value value})
(change-retention
{:invoice-component invoice-component
:ui-key (if (= category specs/ret-ica) :ui/retica :ui/retiva)
:category category
:rate rate})])))
Fixes it, looks like it renders the inputs twice and forces the refresh(defmutation change-retention [{:keys [invoice-component category rate]}]
(action [{:keys [state]}]
(swap! state
(fn [s]
(-> s
(m/set-value* ...)
(remove-retention* invoice-component category)
(add-retention* invoice-component (build-retention category rate))
)))))
@pvillegas12 sorry I don’t have any time next few days to analyze this really at all…other than to say this: The wrapped inputs work by “optimistically” setting their value so that when the async update arrives they are “already correct”. This is a common hack needed in react-based libraries like Fulcro.
In the fulcro v3 plans remember something about using the local state for fulcro props, whould that remove the need for the workarounds on inputs ?
React forms are designed completely around component local state, even for controlled inputs….making them “look controlled” from async changes is always a little bit of a hack.
@tony.kay why would having two mutations in the prim/transact
call work?
I’ve given you all the info about how the things work…I don’t have time to think about it more. ptransact does full-stack one at a time AND it uses setTimeout to defer itself, so you get a delayed and possibly extra addl refresh…perhaps that is why?
ah got it @tony.kay 👍 thanks
Is there an example with fulcro forms, where on field change you call a server to fetch updated values and update the fields?
not that I’m aware