@tolitius it is expensive in the sense that it hits an api with a limit, the limit might not be a problem but I live in China, which means I don't have the best connectivity when I travel so I like to be able to keep state unreloaded as with an atom in defonce. Actually travel or not, internet to outside the Chinese firewall is unstable. Even the (albeit small unimportant) Google office in Shanghai didn't have decent internet, hahah.
I do change the data in the process, so it is kinda ephemeral. I do save it to be application state though.
@bbss: wow that's quite a story :simple_smile:
Heheh, yes, living here is great except for the smog and bad internet.
looks like there are two things:
* this state is mutable
* the restart / reload is "expensive"
I don't have a good answer.. need to think about it..
looks like the usage implies some kind of start-with
path, where you call the real API cache/persist data and then do start-with {#'your/state this-cache}
. when you want to refresh that data from API, you would just call start
... just thinking out loud without knowing the actual context :simple_smile:
also mount should not "restart" a state if you recompile namespace(s) not associated with it
did not add docs for it yet, but start-with
now takes values as substitutes. start-with-states
takes states as substitutes.
Wow, quick turnaround. I can separate the state to a different namespace then didn't try that one yet.
That was what I was slightly confused about, I don't need to call start anywhere in this project and defstates will still work.
@bbss: yes, in cljs, you are probably running in cljc
mode? which would mean that states will be lazily started when they are dereferenced: i.e. @my-state
ah, that explains the "has no deref" errors I didn't understand!
they will also be all started by (mount/start)
, but this is an interesting property of cljc
mode, where the system can be just lazily started
not sure if you had a chance to read this: https://github.com/tolitius/mount/blob/0.1.9-SNAPSHOT/doc/clojurescript.md#managing-state-in-clojurescript
I might need to make it stand out a little more.. since it does not seem to be easy to find from the docs table of context
ah yes I had read it but still very new to all of it so not sure I understood all.
*"table of contents"
ah.. not a problem at all, I can explain
so the whole idea is, in cljs
:advanced
optimization wipes out all the namespaces, and renames all the vars, so we can no longer depend on a var being there to change it's value on start/stop
hence mount has a cljc
mode
(mount/in-cljc-mode)
that would be called anywhere before a call to (mount/start), usually at the entry point of an app: in the -main, web handler, etc.
in this mode states are like simple version of an atom
they don't have all the atom API (i.e. swap / reset!, etc..), but they have a @
(i.e. deref
)
so in order to use the state you would just deref it
right, that's why the double @@ on an atom
(ns app.websockets
(:require [app.conf :refer [config]]
[app.audit-log :refer [audit log]])
(:require-macros [mount.core :refer [defstate]]))
;; ...
(defstate system-a :start (connect (get-in @config [:system-a :uri]))
:stop (disconnect system-a))
if you deref it without calling (mount/start)
it would still work
I see. What would the downside of not calling start be?
i.e. (a little internals): https://github.com/tolitius/mount/blob/0.1.9-SNAPSHOT/src/mount/core.cljc#L130-L132
the system would be started lazily, which means you might expect certain things to start on, say, page load, but they would not be, because nobody needed them yet
e.g. something needs to be loaded, but unless it is referenced anywhere or (mount/start)
was called it would not be (loaded)
got it
so biggest problem would be that it takes a little longer load
that would depend on the use case (app), but I would not say longer, I would say.. it could start certain states at different time
if you need everything to start, and be very deterministic, you can call (mount/start)
okay
Thanks for the explanations!
I like using mount so far.
Hadn't looked at (or had the need to) component yet and found the recent discussions around mount vs component very interesting. Mount seemed like the more light-weight solution.
sure, thanks for you feedback, keep it coming :simple_smile: I am sure we can improve, especially on the cljs
side, so I would be very interested to know what works and what does not / could work better
I am experimenting a bit core.async, I needed a way to switch the way a put was handled for testing purposes and mount seemed good for that with it's start-with.
One optimization I think would be nice is to not reload the whole namespace but just the parts that changed. If I am not mistaken that is what figwheel does.
mount does not reload namespaces :simple_smile:
just restarts states that belong to a namespace that was reloaded
I mean restart all the defstates in a namespace that was editted
it's just a nice-to-have I guess, if I don't want a state to be reloaded I can change its namespace.
ah.. yea, that's a thought. the problem is stale references. for example you have a conn
state that holds a connection to a db
, when a namespace is recompiled, a new conn
reference is created
that is what I alluded to a little earlier: > it might make sense to make this behavior configurable: https://github.com/tolitius/mount#recompiling-namespaces-with-running-states >I feel like, in cljs, it could address both issues above, especially during full page reloads / sending large recompiled increments (by figwheel)
so you could potentially say something like
(defstate ^:dont-reload db :start (connect) :stop (disconnect))
something like that... this is a rough thought :simple_smile:
since I don't think it is nice to cary these ^:dont-reload
around
or (defstateonce) or does that have different semantics
well defstate
already creates defonce
mount has logic to cleanup and potentially restart dirty states
which could be turned off for certain states or for all states..
might be good to have regardless.. i.e. (mount/don't-reload-on-recompile)
, but a better name
I see. Something that still got me stuck sometimes with figwheel and cursive is not understanding how to manage creation of go-blocks. If I were to take from a channel with a go block and change the go block and re-evaluate the old go block would also still grab off the channel until I reload the browser.
I haven't tried that yet with mount but maybe that clean-up logic will take care of that too?
yep, it will, if you provide that logic :simple_smile:
i.e. some kind of a poison pill on :stop
not sure how to remove a go block though
you mean something like this: https://github.com/danboykis/shipper/blob/master/src/shipper/tools.clj#L8-L18 ?
i.e. using a some kind of stop
channel to not recur
anymore
Thanks. That could help me out.
sure, let me know how it goes :simple_smile:
I will, working on different stuff now but I will