This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-11-03
Channels
- # beginners (167)
- # boot (22)
- # chestnut (3)
- # cider (9)
- # clojure (107)
- # clojure-berlin (1)
- # clojure-greece (3)
- # clojure-italy (6)
- # clojure-losangeles (6)
- # clojure-russia (8)
- # clojure-spec (71)
- # clojure-uk (42)
- # clojurescript (186)
- # community-development (1)
- # core-async (12)
- # core-typed (1)
- # css (15)
- # cursive (29)
- # data-science (11)
- # datomic (8)
- # defnpodcast (28)
- # duct (2)
- # fulcro (169)
- # graphql (6)
- # hoplon (3)
- # jobs-discuss (1)
- # kekkonen (5)
- # leiningen (11)
- # lumo (7)
- # off-topic (14)
- # om (1)
- # other-languages (14)
- # portkey (7)
- # re-frame (27)
- # reagent (14)
- # remote-jobs (1)
- # ring-swagger (5)
- # rum (15)
- # shadow-cljs (52)
- # spacemacs (59)
- # specter (78)
- # test-check (3)
- # vim (9)
- # yada (23)
Daily snapshot push of 2.0. The new load marker stuff is in, but largely undocumented…and not integration tested (though the code itself has good tests). You can now do stuff like:
(load this :root/thing Thing {:target (df/multiple-targets (df/prepend-to [:table 2 :thing]) [:table 3 :thing] (df/append-to [:table 4 :thing]))})
I also added the support for better load markers. You can now name them, and they just appear in a top-level table
see the 2.0 branch on github example here: https://github.com/fulcrologic/fulcro/blob/2.0/src/demos/recipes/lazy_loading_visual_indicators_client.cljs
As I coded it, I realized that you need to be able to query for specific markers against potentially many UI components, so querying for the entire table of markers seems like the best bet. It doesn’t come out quite as nice as I’d hoped (you’d have to use dynamic queries for that, and that seems overkill), but it is still a lot better. The default :marker
is still “true” which maintains the old behavior (markers overwrite state).
If anyone is looking to contribute, I have some stuff that could be optimized 🙂 You’d have to be comfortable with recursive queries
So, React 16 seems to work, but I am finding a number of libraries that are not ready for 16 yet. As such, I’m going to leave Fulcro defaulting to 15. If you want 16, you just exclude react from fulcro, and include your own.
@tony.kay for the 15, are we still getting that createClass warning?
I’m using html5 routing and some routes have a routing parameter containing an entity id
now when I’m going to write a query for the components that make up the landing screen for that route, I don’t know how to specify that I need that specific id in the query
@rastandy You can take a look at https://github.com/daveconservatoire/dcsite-cljs/blob/5560c2c6d29725081b5bf9d212c4df12e4698497/src/cljs/daveconservatoire/site/mutations.cljs#L32 for inspiration
as far as I know. You send the bidi-match (handler & route params) to a mutation. And in that mutation you have to add the router params to the state where you need them and then call update-routing-links
to change the screen.
@claudiu wow, a om/transact! call within a mutation? I thought it wasn’t allowed there
@raspasov it's not really recommended, but it's valid
@wilkerlucio ah ok, thanks
just try to don't abuse it, if you can do in a single request, better 😉
because I already found myself putting indents vectors here and there in the app state in the routing code and it seemed not the canonical way to do things
@wilkerlucio @rastandy calling a mutation inside of a mutation is a bad practice. I would not call it even “valid”. You’re better off writing functions on state as a map and composing those.
but sometimes I really don't see other way, on this case for example, I might need an extra call IF the route needs data, but I can only know that after doing some processing that requires environment information (so I start on a transaction)
maybe I could by pre-fetch that by looking at the reconciler, but I'm not sure if that is more clear
@rastandy The short answer to your question is that the parameter ends up targeted at state, not queries. An ident is [TYPE ID]…so the parameter in this case is the ID.
@wilkerlucio well, let’s think that through. Perhaps I’m wrong.
@tony.kay the problem is that I have the id in a routing parameter and the every query for a screen should use the id from the routing param
the thing is, that method builds queries dynamically, how would I do that on a load
?
I feel like we had this discussion before 😛
@tony.kay do you see any problem using the debounce function from https://google.github.io/closure-library/api/goog.functions.html
@rastandy It’s ok. You’re better off debouncing the events, not the mutation. IMO…but if it makes sense to you, then I’m not opposed to it
I need to debounce the calls to the server, without losing the instant optimistic updates
think for example about pagination. Users click fast on various page numbers and only the last page is really loaded and queried to the server
@rastandy i used for autocomplete the gogl debounce. Went with debounce of a function that did transact. Can configure debounce time or not to debounce from the ui, the transact is unaware & reusable.
@wilkerlucio You need a version of load that lets you modify the query dynamically…hm, dynamic queries…. 😜
yeah, I try to use load
and load-*
as much as I can, but when the query doesn't match the exact one on the components, I have to fall back to the direct load call
I’d have to study your example more, but what about your query doesn’t fit into load with params?
@rastandy It is, but in Om Next it has some issues you’d need to understand. Fulcro 2.0 is addressing them.
in my case I might have to change the query, because I want to load a page that comes from an ident
if I just get the query, I don't have the parent context
check this example: https://github.com/daveconservatoire/dcsite-cljs/blob/5560c2c6d29725081b5bf9d212c4df12e4698497/src/cljs/daveconservatoire/site/ui.cljs#L785-L789
so, part of the transformation is to use the component ident + query (that also needs extra data to be built, to figure the ident value), but that has to be injected on the current page query
@wilkerlucio I ended up putting manually idents in my state wherever I needed
I mean, it’s OK to pass the component class as a parameter to a mutation as well, if that’s what you mean
it's derived from the route
the route is the begin of this
from the route the component must be inferred
then I have to load that into a specific place (not on the direct target, to avoid flickering)
maybe I can just load and send the path as a param on the post-mutation
I don’t mean to frustrate you, but we still haven’t distilled it down to a problem that needs a transact inside of a mutation
we seem to have floated to a differnt problem, with the load 😛
but going back to the chian of transacts, I see that if I extract all from the reconciler, I could make some pre-processing before the mutation
but in any way, this code does change the state, that's why it is a mutation in the first place
but there is a branching in the middle of it, because a follow-up read might be required, depending on that specific route needs
so the option would be to pre-process before the mutation, and maybe call a series of then depending on the pre-processing results (to know if a server load is required)
seems possible, but I'm still not sure if that is more clear than just calling from the inside
do you see a different path?
So I would distill this down to this problem: You’d like to customize a query that is loaded. It is the same problem if you’re doing it from the UI or within a mutation, right?
I’ve only given you a way of doing that from the UI (e.g. calling transact with load
as a mutation), and in this case, you’d like the logic to be in a mutation
sometimes that might be no query at all
there are 3 different branches there: 1. route is pure local, no load request needed (this don't cause an extra load) 2. route needs data and can fetch as-is, no query transformation 3. route needs data and customization, process the query and send
@wilkerlucio have you thought about going about the routing issue, with a observable that would track the loads and change the screen
not sure if I understand your question, you mean to observe url changes?
nope, was thinking of listening on the db atom and after page data has loaded & if the screen is the same to trigger the page display in the ui. Just something I was thinking of trying for the router pre-fetching data and only showing the page after the data is loaded. Something like using atom listener as a callback after the page data is loaded :))
humm, gotcha, but honesty I'm a little skeptical about the listening to the atom idea, feels like getting back to watchers/observables, which in my experience is a big source of complexity, I would leave that as the last option if I were to try, but I might be wrong, once you try you tell me 🙂
not sure if I follow it up, the second line about the doing from ui
the idea would be to pre-process the load?
I work better with code examples if you can gimme one 🙂
If you had enqueue-load
that could take an arbitrary query or even load-data-action
from older versions of Untangled, then you would not need transact! here
we are talking about transaction chain, or the use of fulcro/load
directly?
yeah, would be nice to be able to send the queries directly to those helpers
currently it's usage is limited to the exact query (at most filtering with :without
) from the component
The problem with arbitrary queries is that they don’t make sense with the overall model’s parameters (e.g. targeting, markers, etc.)
and in your case, you’re just loading an entity by ident…you just don’t know which one at first, right?
what if we sent both? the component, so you can track it, and the custom query
yeah, the ident has to be built from the route on this case
comp
is already the class on this case
Fulcro 2.0 will make it better, because of the more advanced targeting and load markers
ok, going lunch, we can talk more later 🙂
On dynamic queries: The shortcomings of them in Om Next is that they are tied to a combination of component instance, data path, and class path. Things like component lifecycle transitions can cause surprising behavior. If we’re talking about routing, then the solution is state anyway. The routing-tree mechanism can handle putting the “correct” ident in app state, but that ident could point off into the void (to a table entry that is not yet loaded). All sorts of solutions. To me, this logic belongs in your HTML routing event handling. The example in Fulcro Template just applies the route…but you could also pre-process the route before updating the UI. Add a multi-method hook that can see where you’re going (e.g. dispatches on the bidi match). Carrying around the reconciler at that layer is fine, as is calling transact!
and load
.
Wilker’s solution is also good…just needs to use the primitive load-action
instead of transact!
and load
load-action
is covered in various places…but the essential thing is that it is just like load
, but usable within a mutation.
in terms of routing, the best example is the Fulcro Template, and section M15 of the dev guide
quick question (ident [this props] [:new-user :singleton])
what does singleton mean in this context?
who provides the singleton?
I got it, just wanna know this detail
So, when the initial state is pulled from InitialAppState, IF there is data in the tree for that component, THEN fulcro will normalize it into the app state normalized database. That function will be called to get the ident for the data.
If you don’t include data for it in the startup state tree that matches the component’s location in the UI, it won’t be on the UI or in the db
got it, forgot about the env providing in the om tutorial
Fulcro will allow you to pre-populate your own db with an atom, but InitialAppState is much much much better.
of course, at runtime you can add/remove what you want from the db, and link in things…in any case, if THAT component is on-screen (any number of times) it would be linked by that ident to the single source of data for it
yeah I had a pure om next app before, am trying to provide fulcro for a good routing and parser solution
oh ok
thank you very much, now I have succesfully migrated from yada+compassus to only fulcro on server and frontend 😃
ooof. I’m working on documentation and just realized I don’t cover Ident well in the dev guide…no wonder people are confused.
So, anyone care to check my thinking on this? I know there was resistance to adding anything to mutations that indicate what data they change, but as I’m updating the documentation on mutations it is (again) striking me as odd that you cannot list the follow-on reads there, and since Fulcro 2.0 controls all of the code now, it occurs to me that I can do something about it 🙂
That way, UI refresh would be automatic without having to specify the follow-on reads at transact, and the reasoning about what data changed would be…well..where it is changing
so this:
(defmutation boo [{:keys [id] :as params}]
(action [env] ...)
(keys [env] [:person/name :address/street [:person/by-id id]]))
seems doable and useful.In Om Next the name for the concept is :keys
I think (though it does nothing with them). Now that Om Next isn’t going to be present, we could totally use them to affect refresh automatically.
The idea according to David was that your protocol (e.g. remote side) would specify these as documentation to the reader, but since there is no knowing what the UI-in-question normally queries for, there is no point in pushing them all down to the client. I’m thinking that since most updates are optimistic and local (before being remote), they serve a very fine purpose on any given client (which does know what is being affected locally).
it would also be nice to have that information as data and being able to form a dependency graph for mutations
well, I guess you could pull the parts of the overall graph query that are affected, but don’t see an immediate use for that