Dev workflow question : If i'm debugging a "state complex" thing like a wizard-like group of pages/panels, the state will typically be under the entity-db and kv keys. But that state is wiped out on each start-app!
... So now, each time i save a file, i need to click again in the browser to rebuild the state. Is something wrong with my setup ? I don't think it would be great to have the whole state detail encoded in the url ?
when only using the on-js-reload trick the changes to my components do not show until a hard refresh in the browser
Guess this'll work, i can refresh when state is messed up
i generally had to change most of defs from examples to defn to have a good reload behavior and fast iterations
actually saving the whole app-db thing will mess with the internals, so just save/restore the kv and entity-db parts
doesn't need to be perfect, just easier during dev
@carkh you can pass the :initial-data
attribute to app def when you're starting the app. This will be stored in the app-db atom when the app is started
oh, what shape should this have ?
just like the app-db maybe ?
and merged later i guess
I would do (select-keys @prev-app-db [:kv :entitydb])
allright nice better do it the "approved way"
thanks !
hum i had another question
in re-frame a subscription can subscribe to other subrscriptions
which might be useful for caching heavier computations
is it possible to do this ?
You can do it in keechma too, the underlying system is the same
Both keechma and re-frame use reagent's reaction
macro
Although in keechma it's more explicit
ok good then !
but what woudl be the correct incantation to create a subscription that would go inside that get-kv example
sub> works within a context
when you create subscriptions you will always get app-db as the first arg
and then anything else you passed to sub> as subsequent args
ok so the dependencies would come from where i use it....like in a component (let [my-sub (sub> :my-sub previous-sub)] ...
I would do it like this:
(defn foo-sub [app-db-atom]
(reaction
(get-in @app-db-atom [:kv :foo])))
(defn bar-sub [app-db-atom]
(reaction
{:foo @(foo-sub app-db-atom)
:bar (get-in @app-db-atom [:kv :bar])}))
(def subscriptions
{:foo foo-sub
:bar bar-sub})
ok so if bar depends on foo, i can do {:bar (massage-foo @(foo-sub app-db-atom))}
yes
very nice thanks
and keechma is caching subscriptions on the ui layer
so you donโt need to use form-2 components
when calling sub>
yes
ok that answers all my questions for today =) thanks again !
btw, just something interesting, not completely related - since keechma is not using any globals, you can cut-off app db on the component level and create new one that you manually update. We used this to animate page level transitions on mobile, where you donโt want to change previous page when the next page is being animated in
(defn renderers->components [components]
(reduce-kv (fn [acc k v]
(let [c-meta (meta v)
context (get c-meta :keechma.ui-component/context)]
(assoc acc k
(assoc context :components (renderers->components (:components context))))))
{} (or components {})))
(defn make-internal-ctx [ctx]
(reduce-kv
(fn [acc k v]
(let [c-meta (meta v)
renderer (get c-meta :keechma.ui-component/renderer)
context (get c-meta :keechma.ui-component/context)
components (or (:components context) {})
component-deps (vec (or (keys (:components context)) []))
comp-ctx (merge context
{:app-db (:app-db acc)
:components (renderers->components components)
:component-deps component-deps})]
(assoc-in acc [:components k] (ui/component->renderer acc comp-ctx))))
ctx (:components ctx)))
(defn replace-app-db-in-ctx [ctx app-db]
(let [current-route-fn (fn [] (reaction (:route @app-db)))]
(-> ctx
(assoc :app-db app-db)
(assoc :current-route-fn current-route-fn))))
(defn render-panel [ctx page]
(let [app-db (:app-db ctx)
rendering-page-atom (atom page)
internal-app-db (r/atom @app-db)
internal-ctx (make-internal-ctx (replace-app-db-in-ctx ctx internal-app-db))
watch-id (gensym :transition-watch)]
(add-watch app-db watch-id
(fn [key ref _ new-val]
(let [current-page (:key (get-in new-val [:route :data]))
rendering-page @rendering-page-atom]
(when (or (nil? rendering-page)
(= current-page rendering-page))
(reset! internal-app-db new-val)))))
(r/create-class
{:reagent-render (fn [_ page]
(reset! rendering-page-atom page)
(when page
[(ui/component internal-ctx page)]))
:component-will-unmount (fn []
(remove-watch app-db watch-id))})))
this basically rewrites the deps (both the components and subscriptions), so they all use new app-db
wow gimme a sec to process this
interesting
i've got some stuff to show off too !
i think this middleware-loader can do everything in any context
nice, this looks very useful, I could steal it for our projects ๐
that's more a pattern than code,
i was trying to use the sieppari library to make use of interceptors
which are very nice for separation of concerns
but that would return a promise
and the loader function has to return a vector
or sequence really
anyways you could just replace that eql/middleware by a graphql/middleware and there you go protocol change in a single line of code
yeah, this makes sense
the trouble with the middleware pattern is that everything needs to be synchronous
yeah, which is why they are not really used in Keechma, although I would say that pipelines can act in a similar fashion (as a series of steps that get executed)
i don't know if that woudl make sense to accept promise return values from the loader functions
couldn't use pipelines in this case
yeah - no controller context
although I did experiment with pipelines in server-side context - where I had more general implementation
maybe it would make sense to make a general pipeline lib
the pipeline monad is a good abstraction
i don't know that it would make sense to abstract more, then you're back at general monadic stuff and there are libraries for that already
oh another more pedestrian question
in my app i open a file, so this opens the file dialog, and html only will warn me when the user press ok
so i have this pipeline
that's called inside a pipeline controller each time the user press a button
this pipeline opens the file open dialog box
and waits for a promise that will only be fulfilled when the user press ok
if he presses cancel, that never is fulfilled
trying it
it works well
so the pipeline is re-entered each time the user presses the button
what happens to these pending pipelines ?
They sit there waiting, alone :). I guess that since they are blocked in go-loop, the state stays in memory which could mean it's a slow memory leak
๐
(not that this matters much, unless the user presses that button like a mad man)
If the controller is stopped, I think they should be cleaned up
the pipeline exclusive thing would maybe help with this ?
Hm, this is an interesting one, since the promise is not resolved, it will actually never come to the release step
ohwell not a big deal for me, just a curiosity thing
Exclusive will mark the pipeline as done, but pipeline itself must get to the point where it checks if it should proceed
If it just waits, then it will never happen
Yeah, it's probably not a huge deal, but an interesting problem
alt waiting on a stop channel is the usual thing i guess
Yeah, I'll think about adding this internally
not a problem to me, and most likely not a problem to anyone =)
But now I'm aware of the problem so it's a problem for me :)
haha sorry =)
that's a degenerate problem due to a specification bug in html5
so pretty rare
anyways thanks for your time and good work
women are clamoring for food here ... gotta go feed them
No problem, have a nice day
I think you should not do anythign about this promise thing. If i return a promise, the contract is that I will either resolve or reject it. If I break that contract, that's a "me" problem, not a keechma problem