This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-09-03
Channels
- # bangalore-clj (1)
- # beginners (16)
- # boot (23)
- # chestnut (5)
- # cljs-dev (3)
- # cljsjs (3)
- # clojure (115)
- # clojure-conj (3)
- # clojure-italy (17)
- # clojure-russia (22)
- # clojurescript (20)
- # core-async (11)
- # events (3)
- # fulcro (91)
- # funcool (5)
- # heroku (7)
- # hoplon (5)
- # leiningen (3)
- # off-topic (2)
- # om (1)
- # onyx (9)
- # parinfer (1)
- # protorepl (2)
- # re-frame (3)
- # slack-help (2)
- # spacemacs (5)
- # unrepl (1)
So, I’m working on a convenience macro for the common case. So far, I’ve got this working:
(defsc Person
"A person component"
[this {:keys [db/id person/name]} _ _]
{:table :PERSON/by-id
:props [:db/id :person/name]
:initial-state {:db/id :param/id :person/name :param/name}}
(dom/div nil
name))
(def ui-person (om/factory Person {:keyfn :db/id}))
(defsc Root
[this {:keys [people ui/react-key]} _ _]
{:props [:ui/react-key]
:initial-state {:people [{:id 1 :name "Tony"} {:id 2 :name "Sam"} {:id 3 :name "Sally"}]}
:children {:people Person}}
(dom/div #js {:key react-key}
(mapv ui-person people)))
The basic syntax is:
(defsc ComponentName
optional-docstring
[thissym propsym computedsym children]
options-map
body)
where options-map
can be used to generate the query, ident, and initial state. It does not support more advanced cases…defui is really the general utility. Just trying to save some headaches for the very common component case
options-map
:
- :children
(optional) a map of keyword to class. Generate the query join, error checks your destructuring of props, and helps initial state generation work
- :props
a vector of the scalar props. Generates query elements, and error check destructuring
- :id
(optional, defaults to :db/id). Needed for ident.
- :table
(optional) The table side of the ident. If not supplied, you don’t get an ident.
- :initial-state
(optional). A map of key/value. Checked against queried props. Value for scalar props can be a scalar value OR the special :param/XYZ
, which will pull the value from incoming parameters. Value(s) for children can be a map or a vector of maps which are treated as parameters to an automatic call of (get-initial-state ChildClass p)
. The value(s) in the option map(s) can be scalars or :param/XYZ
.
I’m still playing with it, and am not ready to release, but if people have feedback/input before it becomes API I’d like to hear it.
Oh, and it does the ^:once
bit for you as well. Thinking about adding in automatic generation of a deref factory with react key based on id (if there is an ident)…so you could do this:
(@Person person-props)
. Still thinking about the options here. I think I fancy a deffactory
more, since you can name the symbol then, and possibly have a bit more control. Thinking on it.
The error checking is quite nice, actually…it makes it much harder to write broken UI code.
I have to say: after playing with it a bit, I really like it. It caught more than one mistake I made as I coded up the devcards for it, and reported the problem in an easy-to-understand way.
I just pushed fulcro-1.0.0-beta10-SNAPSHOT with the new macro (fulcro.client.core/defsc)
. That will allow anyone to play with it easily to give feedback. NOTE: The API for it is not considered stable, but it is fairly well-covered by tests, and seems to work well as far as I’ve tried it.
@tony.kay Cool, makes total sense. Probably should not have mentioned component, the thing that I seem to be repeating is sending the component ident (ref). Mostly use post-mutation for loading flags, that i have in the component. currently send it as param, to avoid hard-coding it in the mutation.
I see. The ref is possibly somethign that could be automatically included, since it is data.
Hm. Composing in mutations is a problem…there is no way to know ref in load-action
, for example
Yeah, it’s really not a good idea I don’t think to mix :ref
into the post mutation environment. It would make people expect it there, and there are just too many circumstances when it cannot be supplied:
(load @app ...)
(load reconciler ...)
(load parent-component-during-callback ...) ; wrong one
Inside mutations:
(load-action app-state-atom ...)
Frankly, it would be easier for you to write a wrapper for load
that automatically augments your post-mutation parameters with a standard parameter. Then you’d know the limitations, and have the convenience.
@claudiu This is untested, but should be close:
(defn refload [component-instance keyword-or-ident QueryClass config]
(let [ident (when #?(:clj (satisfies? om.next/Ident component-instance)
:cljs (implements? om.next/Ident component-instance))
(om.next/ident component-instance (om.next/props component-instance)))
config (update config :post-mutation-params assoc :ref ident)]
(load component-instance keyword-or-ident QueryClass config)))
Actually, it should work just as well as load…ref just won’t show up if you use a reconciler or app
Namespaces:
[om.util :as util]
[fulcro.client.data-fetch :as df]
[om.next :as om]
If using cljc you’ll need to import IdentI tuned it up a bit…update tolerates nils well, so all that checking wasn’t necessary
It's a really small thing, was curious why it's not there if it's a design decision. Makes sense not to add it given load-action 🙂
Still a lot of details to figure out. So far think I'm getting close to breaking even for this project, if I would have used js & python. Initial learning curve but things are going really smoothly and fast now 🙂
of course you can just call that function load
and make your own data fetch namespace 🙂
ahh yes 🙂 Don't know it the benefits would benefits will outweigh the cons. So far everything is almost perfect.
Only the fact that I can't use load
on ssr seems to be missing. Still pretty awesome to have ssr, user experience is really nice 🙂
So, load on SSR…I think all you’d need to do is write a mock networking implementation for the server-side…I think it would be pretty small.
hmm would be crazy if it would work 🙂. Really pressed for time until the end of this month, but will give it a try afterwords.
You’re currently my biggest contributor on patreon, so I may just try it for you later today 😉
was thinking of custom networking like in the restful api in getting started, and just hook it up there with the fulcro-server. Is that what you mean or mocking as in testing ?
the former…it is just a protocol with a send method…instead of doing network stuff, call fulcro-parser
the implications if it would work are pretty nice. Just put in componentWillMount the initial loads, for ssr should have a fully populated page out of the box, with the same code that you use on frontend when doing routing.
in nodejs componentWillMount
is the only one that runs on ssr. No idea if om-next mimics this behavior.
starter callback where I can call component static method that can use load inside sound really nice 🙂
@claudiu As I thought: rendering to string is written in om.next by hand. There are no lifecycle calls
so not exact react behavior. In the react docs it says "Generally, we recommend using the constructor() instead." & figwheel also seems to trigger the method for every change to the file.
remember that figwheel changes the root level key, meaning react will throw away the DOM an rebuild it…which will trigger all lifecycle mounts I thnk
another reason to embed your load behaviors into mutations…avoid the UI-based side-effects
I never touch the react lifecycle unless I need it for the DOM…focus, ref to a canvas, that kind of stuff
but apart for componentWillMount and routing. Is there another place where to put the initial loading markers, and load ?
make your own routing mutations…the routing namespace has functions for composing routing into your own mutations
route-to-impl!
will work for composition when using all kinds of routers (including dynamic). update-routing-links
works for just the standard union-based.
totally missed that idea. Will move the initial load into routing mutations, for most of my use-cases think dynamic router is a better match. Haven't had time to look over it, as soon as I got routing working, focused my attention on other areas.
re-pushed SNAPSHOT of beta10 to clojars. I’ve hammered on defsc
quite a bit, and think it is pretty close to API-ready. I fixed up initial state parameterization support, and documented it in section M05 of the devguide (not live, just on develop). It really makes writing most components a lot cleaner and easier. It could easily be exnteded to support react lifecycle as well, which would go a long way towards making it the only solution you’d need. The API it has should still be considered relatively unstable.
@currentoor @mitchelkuijpers @wilkerlucio @gardnervickers ^^^ I think you guys will like this, assuming you’re not using a lot of custom protocols on your components.