This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-06-29
Channels
- # aleph (2)
- # architecture (1)
- # beginners (5)
- # boot (7)
- # cider (24)
- # clara (28)
- # cljs-dev (7)
- # cljsjs (3)
- # cljsrn (24)
- # clojure (145)
- # clojure-italy (2)
- # clojure-nl (7)
- # clojure-uk (54)
- # clojurescript (159)
- # cursive (49)
- # data-science (8)
- # datomic (23)
- # editors (10)
- # emacs (2)
- # fulcro (123)
- # graphql (12)
- # hoplon (2)
- # java (23)
- # jobs (1)
- # jobs-discuss (2)
- # leiningen (17)
- # mount (5)
- # nrepl (5)
- # off-topic (20)
- # om (2)
- # onyx (25)
- # parinfer (2)
- # pedestal (1)
- # re-frame (8)
- # reagent (7)
- # ring-swagger (1)
- # shadow-cljs (24)
- # spacemacs (7)
- # specter (6)
- # tools-deps (7)
- # vim (2)
Fulcro 2.5.11 on Clojars. This release cleans up networking just a bit. I found some minor issues while creating this file upload demo: https://github.com/awkay/file-upload-demo Also Fulcro Inspect had a few little issues around networking as well, but those are fixed in Inspect beta8 (which is currently a snapshot).
I also just updated the book some with respect to middleware docs: http://book.fulcrologic.com/#_client_response_middleware
@tony.kay do Follow-on Reads (in prim/transact!
) trigger ui refresh if the component is the reconciler?
does that mean follow-on reads are obsolete there?
thanks
@tony.kay in the patreon post you mentioned shadow-cljs and mount. Is mount the lib you preffere between component/integrant/mount ?
Iāve recently started using mount and really like it. Cleans up things quite a bit, actuallyā¦a lot less OO
I just put an update in the book http://book.fulcrologic.com/#_rolling_your_own_server
that little bit of code is most of āeasy serverā, and integrating other āthingsā with it is as simple as throwing them into the env in the wrap-api
The Duct framework used component but now uses Integrant. On my side I really like Integrant.
after looking over the docs, I still think I like mount better personallyā¦part of what I really like about it is that you donāt have additional config to manage. In component youāve got to ābuild the systemā out of OO components. In Integrant your āconfigā isnāt even easily coupled to the code that does the actions (defmethods are not well supported by nav in IDE/editors). In mount, you just defstate
things and require them. Itās eliminates tons of cruft, but still gives you the power to āsub outā parts of the system. More importantly: navigating the code is natural and supported by the IDEā¦want to know where that āconfigā thing is coming from? Hitting ājump to definitionā in the editor takes you right to the defstate
.
The biggest possible downside is: if you require it, you get it. So, stale requires in a namespace can accidentally start up something you didnāt need.
My current library recommends when building a new business software project are pathom, mount, promenade, clara rules, datomock (if using Datomic). Iām playing with immutant web server instead of httpkit, and it seems good so far, but nothing has stood out about it for what Iāve done to date (other than the benchmarks are better).
i'm building a personal fulcro app; i know i want to use datomic/datascript for the database, and i've been considering using clara for the logic, but it's less clear to me how using that would work in the context of fulcro (as opposed to e.g. precept). how do you approach it?
@U61HA86AG the client fulcro has its default parser. No idea how easy it would be to have the state in datascript. Think this is what you're looking for
@U3LP7DWPR you can run datascript on the server as well, that's what i was referring to. i think the default db format works well on the client.
So my first thoughts are that I wouldnāt want a truth management system running the UIā¦because the UI itself is a very contextual thing, so it seems that the rules would get unwieldy. But this is my first exposure, so I want to let it ābakeā in my head for a while and read their examples.
Interesting - reminds me strongly of Arachne's FactUI: https://github.com/arachne-framework/factui
The short answer that comes to mind, @U61HA86AG, is that you could replace the client database and parserā¦the parser query-side would query for āfactsā in Clara, and the mutations would insert/retract facts. Not sure how it would perform, but it would give you a clear decouplingā¦that said, youād be back to Om Next since youād then have to figure out how to do the data-driven networking story and graph queries.
My current use of Clara is for more focused problem solvingā¦e.g. shopping cart business rules. Insert some items in the cart, run rules, then run queries about things like shipping charges and discounts. Then persist those āresultsā to the UI database. It isnāt āautomatic UI updateā in that sense, but it gives me a more functional interface to using rules to replace hand-coded logic. I see Clara as a big function I can call to do complex logic and return a result (rather than side-effecting in the rules themselves, which irks me)
Youāve got this beautiful rules engine that is completely immutable, and yet everyone still wants to side-effect external changes. Itās convenient, but truth-management is hard to tell how to āundoā side effects.
So, what these UI frameworks are doing is tying the UI to facts in the database by you defining queries that feed the UIā¦so inserts/retracts from the rules update the UI
thatās pretty coolā¦Iām still thinking about how that functions with the ārest of the storyā that you needā¦like server integration.
i really like Fulcro's client-side and networking story, but i feel like the server-side is more open-ended (with good reason). that clarifies things re: how you use Clara. interesting! i think facts and rules engines are a really cool idea, so am always curious about how they're used.
Thereās almost certainly an integration story here where Clara could maintain facts, Pathom could run graph queries against the Clara queries
might be interesting to make āderivedā data be Claraā¦e.g. put in a parser that uses the client database for hard data, and let certain keywords trigger queries for clara facts. Then mutations would insert changes into the client db, and add/retract relevant facts to claraā¦refresh of UI would then automatically update derived data from claraā¦all sorts of possibilities.
Iām sure my list will expand as I find further holes. The promenade library has a lot of alternatives, but I liked his approach to a monad-like error handling. I think the library could probably use a bit more, but itās a nice clean start.
I have not used Mount at all, and I didnāt mean to push you in the Integrant camp. I used Duct at work hence itās ācloserā for me.
another Duct fan here š
@tony.kay there is a root render on the transact on reconciler, even if the user send an ident too?
@wilkerlucio good questionā¦I donāt remember on that case
so, reviewing the render code I may be misrepresenting what using the reconciler does.
transact itself queues the ident of the component, OR the explicit ref (if given), and any declared refreshes on the mutations that ran. So @myguidingstar I think I misled you. I was thinking about swap!
on app state, not transact on reconciler
transact is always a targeted updateā¦I obviously was not awake enough when I answered that question
it auto-queues the component if it has an ident (which the reconciler does not). Using the additional ref arg (as Wilker points out) is a substitute when using the reconciler and you want :ref
to be in the mutation and refresh list.
I thought there was a code path that said āif nothing is queued, then root refreshā, but Iām not seeing that as I look through the codeā¦so a transact on reconciler with no ref or follow-on reads would refresh nothing. I need to test that, because that is not an intended behavior
@tony.kay to me the current behavior was my expectation, I'm afraid if we don't send nothing we might get unintended heavy refreshes, if this is the state I would prefer it stays that way since it's already that and for "easy refresh" we have the keyframe mode, so I rather keep the "advanced" mode to be more performance driven than easy driven
So I would disagree: If you use the reconciler and queue nothing for refresh with follow-on reads or a ref, then youāve clearly changed the app state and a UI refresh should occur. In the absence of any way to choose what to refresh, a root render should happen.
99% of mutations will be against components or have follow-on reads. Optimization is opt-in by specifying idents (which you want anyhow).
not nescessarily, you could be swaping something that's not currently visible, that would not need any UI refresh, in this case the root render will be a waste
but no props will change on the query result, so nothing will actually happen at the react layer
still overhead, I wonder how much, I think it's worth measuring
ah, it would stop at the root? or it will call everything?
it's like force root render (which will force everything down to refresh) or it would do a normal root render which can stop at the root element?
So: 1. Your query+refresh should be tuned (e.g. via unions) to run in 10-30ms. In practice this is normally easy to achieve. 2. shouldCompontentUpdate stops tree traversal on no data change. A ārootā render would short-circuit the entire React system on no-visible-changes The only case youād really want to avoid root render in this scenario is if youāre doing frequent updates (e.g. many times a second via reconciler) of non-visible data to avoid the query CPU overhead
yeah, in this case I think it's ok, I was with the impression it would be a force root render
@tony.kay i see last night you shared your current library recommends when building a new business software project, so you don't use specter anymore? or is that just not a critical part of your stack?
oh, I like specterā¦I think it is a great library, tooā¦just havenāt edned up using it as much in practice
partly that is my lack of time to learn it btter when there are solutions that āworkā that I alraedy know š
Thanks for reminding me of itā¦I keep meaning to get more practice with it, because I do, in fact, think it is a super-nice library for general-purpose work
I really like the specter ideas too, but I find myself ending up just using the clojure basic things, they solve 90%+ of the cases, so I end up not using specter
(I also don't like that he decided to use uppercase for a lot of things there, looks ugly...)
In practical terms thatās how Iāve been as well; however, whenever I look at the library I think āI really need to learn thisā¦it would make so many things less verboseā. Uppercase is less desirable, but where that is slightly ugly, the sheer concision is a big boon. Iām adding it back to my list of things I should really spend a day learning well
the other issue that I worry about is that if you write a bunch of stuff with it, it might make contributors on OSS harder to find because they donāt āgetā your codeā¦but I think that is wrong-headed
I think the uppercase is actually a good decision, since it allows you to refer all without stomping on a bunch of accidental collisions.
specter can be very useful when dealing with tasks like garbage collection
maybe, but I dislike the :refer :all
in general, I see it as a bad practice (with a few exceptions, like for testing primitives I found it ok)
i like :refer :all
in some cases, limited to namespaces that have a very specific purpose, like testing files
i used specter for dealing with the salesforce API, i first wrote a few components in vanilla clojure then converted them to specter, specter was clearly better suited for that
i've been writing business apps for almost a decade but i've never used a rules engine š
should i be ashamed?
@currentoor nopeā¦mostly havenāt either
does using something clara really help in this domain?
and rules engines in general
Declarative logic is just handy, especially if it is a complex set of intertwined rules
i see
and sicne the rules can look more like the problem domain, it is an easier translation from stakeholder to code
I just wonder if anybody is using core.logic these days š
Clara Rules is something I would love to experiment some time, seems interesting, but I dont have the feel on what they look like in real case scenarios
yeah same here, i'm just worried about adding it to a core part of my stack then regretting it
so i decided to only use the CSS part of semantic ui and removed all the js factories
everything was straightforward except the modals, i wanted to get a second opinion on that
(defsc Modal [this {:keys [show?]} {:keys [header content actions]}]
{:query [:show?]
:ident (fn [] [:modal :singleton])
:initial-state {:show? false}}
(if show?
(div :.ui.page.modals.dimmer.transition.visible.active
{:ref (fn [el] (if-let [s (and el (aget el "style"))]
(.setProperty s "display" "flex" "important")))}
(div :.ui.modal.transition.visible.active
(when header (div :.header header))
(when content (div :.content content))
(when actions
(div :.actions
actions))))
(div {})))
(def modal-factory (prim/factory Modal))
(def ui-modal (fn [props ui-opts]
(modal-factory (prim/computed props ui-opts))))
(m/defmutation set-modal-state [{:keys [show-val]}]
(action [{:keys [state]}]
(swap! state assoc-in [:modal :singleton :show?] show-val)))
(defn show-modal! [comp]
(.add js/document.body.classList "dimmable")
(.add js/document.body.classList "dimmed")
(prim/transact! comp `[(set-modal-state {:show-val true})]))
(defn hide-modal! [comp]
(.remove js/document.body.classList "dimmable")
(.remove js/document.body.classList "dimmed")
(prim/transact! comp `[(set-modal-state {:show-val false})]))
(defsc CompUsingModal [this {:keys [modal]}]
{:ident (fn [] [:packages-table :singleton])
:initial-state {:modal (prim/get-initial-state Modal {})}
:query [{:modal (prim/get-query Modal)}]}
(div
(dom/button {:onClick #(show-modal! this)}
"show modal")
(ui-modal
modal
{:header "foo"
:content "bar"
:actions (div :.ui.button {:onClick #(hide-modal! this)}
"close")})))
semantic ui requires !important
but react inline styles don't support it, so i have to use a :ref
semantic ui does modals by appending modal elements to the bottom of the body
but i'm able to get it to work "inline"
is that an ok thing to do?
another approach i suppose is to render the modal component at the bottom of my root and use app state to coordinate what goes inside there, seems like that's how semantic ui does it under the hood, but then i loose contextual reasoning
is there a way to tell a mutation to do something with new ids (aka resolved values of tempids from server response)? Listening to all transactions seems overkill. I want to set html5 route to a new url containing the new id after user hits the Save button
can you do it with a post-mutation?
in the past i did something like that with a react lifecycle callback, componentWillRecieveProps
or something like that, but there's probably a more elegant way
no, I can't. Post-mutation requires you to know its params in advance, not waiting till server response
Well then the react callback is always an option right? Just update the html5 route in there if the old pros have a tempid and the new props have a real id
Assuming the components that depends on this tempid is rendered while the url has the tempid/real-id
sure, it's an option though I prefer things go thru fulcro's transaction system
yeah i see what you mean
@myguidingstar maybe the new ptransact!
?
Is anyone planning on submitting anything related to Fulcro/Pathom for Clojure/Conj this year?
Thatās a great question. I think the most interesting talk would be if we could get @wilkerlucio to submit a pathom/graphql/fulcro kind of talk
surely would be fun, not sure what, but I'll probably try sending a proposal š
maybe pointed just a bit more towards a full-stack Fulcro app with GraphQLā¦but I think the first 1/2 to 2/3rds could be very similar.
Very cool guys. I'm always interested in hearing what you smart folks have to say.