petterik / lajter Goto Github PK
View Code? Open in Web Editor NEWLicense: MIT License
License: MIT License
Notes from textedit post clojure conj 2018 post hammock.
Cares about:
Does not (necessarily) care about:
Cares about:
Remote query is a merge of:
After merge, extract .
How are queries merged?
Local Reads and Merge both care about ID specification
There's something about the property "full-name" that should be possible to do locally when there's a "first-name" and "last-name" in the GraphQL.
Regarding reverse lookup, that's a backend concern, and that's fine (it seems).
Domain Model
Root Queries
View Queries
Normal Model
View data, such as:
One use case:
When layers contain remote reads to the same remote (no mutations), they can be batched and sent as one request.
We can support * in view queries as we know all the fields of the model.
Good idea or bad? We stopped using * in sulolive, but if we were able to expand * to all the known fields in the entity, would we have kept on doing it?
The initial root render & parsing is unnecessary when doing SSR.
The only thing you want is:
We did this with sulo by avoiding the code that called the other stuff.
From clojurians #fulcro slack
(defsc MyComponent {:ident ... :query..}) ;; no render
(def MyComponentWeb (extend-component MyComponent {:life-cycle-methods ...})
(def MyComponentRN (extend-component MyComponent {:life-cycle-methods ...})
Allow user to add/remove data to the app-state whenever layers are changed.
Call update-state! a bunch of times to see if the state gets set correctly.
Example:
(doto this
(om/update-state! assoc :foo :bar)
(om/update-state! assoc :abc :xyz))
Actually, do this with transact as well, to see if the props are correct.
A component may not always render every child, there may be conditions to them.
A router - for example - will most likely only render one child at a time.
Similarly to :lajter/children
, :lajter/routes
should be defined before trying to render it.
The big idea of om.next (imo) is that UI's declare their data requirements as data. Datomic's pull pattern syntax was a good way to achieve this. Depending on how clojure.spec decides to express spec's as data (which has been hinted now for a while), we may want to declare our queries in that format to get leverage from all the tools that are built upon that data format.
We could also check the clojure.spec registry whether a query key (root or field) is spec'ed and do validation on it.
Not sure what to go for here.
People seem to like defsc from fulcro?
(defsc [this props]
{:query ..
...
}
(dom/div nil "foo"))
I'm not so sure?
Use case:
Does:
Solution(?):
The p/to-env
implementation of the reconciler is pretty gross.
See if there's a better way to structure this code. Maybe put latest-db-from-layers!
somewhere else?
Make the reconciler stoppable to provide a path to remove any state and stuff.
Make the reconciler suspendable, to prevent renders, sends and stuff when code is reloading. When resuming the reconciler, it can clear caches that are no longer valid as code has been changed.
One of the things lost going from REST to om.next is remote mutation responses. Maybe even reads?
Where do we put them? We want to be app-state agnostic.
Into a layer? That's sweet?
Layers are also an answer to "is my request pending or not?".
Could add new functions for interacting with a component that doesn't have to pass this
Example:
;; instead of:
(dom/button #js {:onClick #(la/update-state! this (fn [state] (assoc state :foo :bar)))})
;; Could have:
(dom/button #js {:onClick (la/update-state #(assoc % :foo :bar))})
Notice that:
this
is gone.#
char is not used to create an anonymous function.!
removed. Not sure if that's good naming.Same for transact, possibly for the computed functions as well and others?
There's more to implement for react, like Context.
See: https://github.com/tonsky/rum/blob/gh-pages/src/rum/core.cljs
And: tonsky/rum#165
(when (not= (-> c p/clj-props re/props-basis-t) (:t @state))
;; render
)
Children of a component must be declared in :lajter/children
and calls to (render-child this child)
should throw exceptions when called with a child that's not in the already defined children.
{:lajter/children []
:render (fn [this props state]
(lajter.core/render-child this Child))}
;; ^^^^^^ is not in :lajter/children
;; This should throw
lajter.model/gen
could be extended to only generate a selected portion of the pattern. Not sure where, but it seems like it could be useful?
Add, replace, delete? layers.
Resolve layers during reconciliation?
It's a mess.
Layer application can be quite harsh on the rendering. Experiment with making it async, only committing when all of the layers are applied.
Update props and re-render (via .forceUpdate
) a component that's not the root component.
Also, we should re-render the components with the lowest depth first, such that we don't over render. See: https://github.com/omcljs/om/blob/master/src/main/om/next.cljc#L2777
Use case:
Code is loaded async and there may need to be new routes and new components (that aren't loaded yet) that has to be added to a components routing map on demand.
With sulo, we added a new root to the reconciler whenever a new module was loaded. Same approach here? Or something less "dramatic"?
:layer.merge/value
and :layer.snapshot/db
can sometimes be garbage collected. It's not a big deal during development, but it reduces the memory foot print which is nice for production.
We shouldn't have to re-calculate all the layers at every reconcile!
. Use the most recent app-state as a base when the layers hasn't changed.
Incrementally update the app-state whenever layers are added.
;; Given
{:state {}}
;; Adds layers 1 2 3
{:layers [1 2 3]
:state (db/with-layers {} [1 2 3])}
;; Now adding a new layer: 4, should calculate:
{:layers [1 2 3 4]
:state (db/with-layers (db/with-layers {} [1 2 3]) [4])}
;; Where the first db/with-layers have been cached.
Given component:
(def componentA
{:query [{:query/foo [:a]}]
:children [componentB]})
(def componentB
{:query [:query/bar]})
When :query/bar
changes, only update componentB
.
transaction listener like om.next
Use case:
;; Given query on a (visible) component:
{:query [{:read [:a :b :c]}]}
;; When transacted:
(la/transact! this '[(remote/foo) :read])
;; Remote query should be:
[(remote/foo) {:read [:a :b :c]}]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.