alright, here’s been my big WIP for the last month or so: https://github.com/Lokeh/serenity still WIP but is actually pretty close to being release worthy IMO
TL;DR it’s like reagent’s ratom/reaction lib, but a little more disciplined and setup to one day interop with a Concurrent Mode-like scheduler
what do you think of resuming being disabled in react? For me this feature was the biggest pull to it, without this, I am not sure async rendering is really worth it even.
i mean concurrent mode by async rendering
I haven’t looked at the latest stuff w.r.t. async rendering pausing/resuming in React
have they nixed it from their roadmap? or just disabled it while they fix it
This is fantastic, I like it. I was expecting to have an immediate desire to shift the api, but it matches really nicely with how something like this should look. I'll have to dig in to how this works with react and local state, but this is exciting!
Is a sink just an action in reaction to a source changing? Any reason to not support add-watch instead of a specific api?
that means a lot, thanks for the glowing feedback ☺️
yes, a sink is an object that represents an action in response to a source or signal changing
It's not actually an action itself then. So it matches the semantics of watch?
One upside is the lack of names, but one can solve that other ways.
yes, it might be just aesthetics
I’ve based a lot of the underlying mechanics of the library on an OCaml library called Incremental, which has separate “observers” that are distinct from computations
observers just watch a computation and fire an on-change handler, like sinks
While I like your aesthetics, I think it's better to learn less things and copy the language's existing pieces.
one benefit (I think) is that this simplifies garbage collection and cutting off computation of nodes
I'm lazy, less things to learn :)
like imagine if/when an API to hook into the GC for v8/etc. is implemented
once a sink goes out of scope and GCd, it can then automatically dispose itself and all connected signals
harder to do that with signals because they potentially have many different connections
but maybe it doesn’t really matter and it would work with add-watch too, it’s all just theory
the other nice think about sinks is that they are always a leaf in the fully connected graph
so imagine you had a utility that drew a graph of all the nodes that were connected to the thing that is causing your component to re-render
since you have a sink, you can hand it to that utility and be guaranteed to only see the part of the graph that your component depends on
actually, that would probably work with signals too since I separate edges to the node and edges from the node...
You could do that watch key as well, the distinction is reification through key or reification through var.
yeah, i guess it feels a little weird to have add-watch / remove-watch be side-effecting, in that adding or removing watches may cause a signal to come alive or go dormant
Minor typo at the require in the README [serentiy.core :as s]
and having specific nodes that are only for side-effects pleases my pure FP architecture astronaut sensibilities
but you are convincing me :P
oo thx!
The lack of remove might be a relevant thing that I've overlooked.
But I find it strange that it doesn't have a remove now...
there’s a dispose!
function which is essentially remove
it’s just not in the README. the example is not exhaustive
Without looking at the docs, I'd know how to remove it if it was remove-watch 😛
@lilactown do you envision this being used in a let or in a global? Thinking wrt to react
:thinking_face: is both an acceptable answer?
it's not like recoil, which needs global unique identifiers
the primary use case I would expect w.r.t. React is to have serenity sources for things like remote data caching; state that you need to live completely outside of the component tree
so you might have some sources/signals/sinks that are def
ed at the global level, but then inside of components you could use a hook like:
(def dbA (s/source ,,,))
(def dbB (s/source ,,,))
(defnc my-component []
(let [data (use-signal #(merge @dbA @dbB)) ;; dynamically creates a new signal and subscribes to it
,,,]))
Both is the best answer. It indicates your thing is simple.
yeah it's very much in the same vein as reagent in how dynamic it is
I believe it's only temporary, but the point is that it was enabled and react was very performant, but now, although it still can (probably, haven't checked) suspend long renders, it can't resume, needs to start over from scratch, throw away intermediary steps. What's the point of fiber then?
yeah it sounds like they're working out the kinks!
I have a different sentiment about this. They are having trouble finishing suspend because it's a bad idea and every demo assumes too much knowledge ahead of time, something that React usually avoided so far (small surface API). So suspend works (afaik) like this, but not with resuming, and for branding purposes they are committed with suspend, that's why performance is not an issue. But it is an issue if you want to use react for not-a-website.
that's a pretty pessimistic way of looking at it 😛
could be, but pessimistic doesn't necessarily mean inaccurate 😉
I want to make that sierpinski triangle demo work, with or without react