Fork me on GitHub
#reagent
<
2018-07-13
>
justinlee17:07:51

does reagent start re-renders synchronously on when a ratom has been changed? it looks like it does but i can’t think of how to do an experiment to confirm

justinlee17:07:12

and by “re-renders” i mean on the reagent side. i realize on the react side it batches

mikerod17:07:19

@lee.justin.m don’t no how to experiment it either, but think it is batched/async

mikerod17:07:32

well, it depends on what is reacting to the ratom change

mikerod17:07:46

but if you mean a component render, it is in a Reaction

mikerod17:07:33

So I believe the reactions are added as watchers on the ratom. The way a reaction reacts to a change notification is by registering itself “dirty” and being placed on a queue

mikerod17:07:49

At least this is my understanding of things

justinlee17:07:48

well actually i think this is a test, which indicates that it is batched:

(def test-atom (reagent/atom "foo"))

(defn a-component
  []
  (print "a-component")
  [:div @test-atom])

(defn test-component
  []
  (print "test-component rendering")
  [a-component])

(js/setTimeout
  (fn []
    (print "Pre reset")
    (reset! test-atom "bar")
    (print "Post reset"))
  0)
=>
test-component rendering
a-component
Pre reset
Post reset
a-component

justinlee17:07:41

i am getting side effects happening in my program in between pre and post and i don’t understand why and now i can see the re-framers saying I told you so 🙂

mikerod17:07:39

yeah, I think that test shows it

mikerod17:07:05

I’m a re-framer too though, so told you so (I guess) 😛

Hukka17:07:56

@lee.justin.m Haven't checked the implementation, but I recall reading that it's either an reagent or re-frame feature to do updates only when RAF hits

Hukka17:07:20

So if there are quick enough updates, some will not ever be visible even in the virtual dom

justinlee17:07:58

i know for sure that reagent batches react updates in a raf, but the question i had is when does the reagent cycle run with respect to atom mutations

justinlee17:07:32

something in my code is causing the reagent renders to happen synchronously. i don’t really understand why that’s happening.

justinlee17:07:58

it’s the one time i really miss having a stepping debugger

Hukka17:07:25

Hm. I know it's a bit odd place to look for it, but if the reagent docs don't comment on that (and they are pretty sparse), it might be explained in re-frame docs

Hukka18:07:02

They seem to give credit where it's due, and IIRC re-frame subs are also async and batched

Hukka18:07:20

Of course, it might be just faster to look at the code...

justinlee18:07:45

that code is beyond my skill level. there’s a reason why we can’t get anybody to volunteer to document the reactions/tracking functions 🙂

mikerod18:07:33

@lee.justin.m I’m curious though, what happened to the original author of these things? I don’t know that I see a presence of them around the slack channel, and not sure on GitHub either.

justinlee18:07:24

@U0LK1552A I’m just as curious! Dan Holmsand or something like that appeared to have written everything and then he just dropped off the map as far as I can tell. It’s really interesting how these things happen.

justinlee19:07:28

I think I’ve asked Juho before if he knew anything but he didn’t.

mikerod19:07:57

ah a mystery

mikerod19:07:07

Yeah, I’ve seen that Dan appeared to do a bunch

mikerod19:07:16

It’s a really popular lib and I am often confused who runs the show

mikerod19:07:40

which is Juho I guess

justinlee19:07:49

When I did the documentation project I was really frustrated because it would have been awesome to have someone to just explain the thought process. He did SO MUCH WORK on the project including awesome documentation I’m a bit surprised that he’s totally checked out.

mikerod19:07:04

yeah, it is odd

mikerod19:07:32

he is like the Santoshi of cljs

justinlee19:07:03

I think Juho stepped in at some point. He’s kind of a wizard. I have wanted to start helping with maintenance but I think I would need someone to really help me figure out WTF some of this stuff is. I understand a lot of reagent now but I still run into things that just baffle me (like how the react component caching works)

justinlee19:07:08

that’s funny

mikerod19:07:22

his twitter and github seem dormant too

mikerod19:07:54

well thanks for the info, I knew you did work on the docs etc and I was following along, but was confused why the main author has never chipped in before - and now I know it is a mystery

kennytilton22:07:59

This is a little scary. I have been thinking about doing a blog series on various reactive hacks out there. And as we speak I am trying to conjure up an example that will test if ratoms are susceptible to glitches.

mikerod22:07:14

One of these days I’m going to try to go through the impl enough to doc some of it. I’ve followed through it before and generally can understand it. But yeah. Need a deep understanding to find edge cases.

mikerod22:07:04

Some of the trickiest parts is how different reactive objects hold links to each other. And how there are various caching mechanisms they use for apparent performance gains.

kennytilton22:07:41

I am going to take a peek at the code now, I am curious what mechanism might be in use. Some libs use transactions, MobX uses mark-and-sweep. I am an outlier, I use an integer “pulse”.

mikerod22:07:37

Yeah you have some background in various techniques. May be good for gaining insights.

mikerod22:07:51

The good news is is the core of the codebase for reagent is pretty small.

mikerod22:07:07

Just has plenty of little details to try to follow. Hah

kennytilton23:07:18

Damn, that code looks familiar. I always, say, the problem determines the solution.

kennytilton23:07:28

I got excited when I saw ratomGeneration thinking it was my pulse but it seems to be just for dev/debug.

kennytilton23:07:57

“apparent performance gains” Yes, depending on the application, caching can be indispensable to the paradigm performance-wise.

mikerod23:07:40

Yeah makes sense.

kennytilton01:07:15

In effect, the caching is what makes what I like to call functional state feasible. When we stumbled onto dataflow we just wanted functional state, but we were doing complex GUI layout computations so performance forced us to track dependencies so we could propagate intelligently and minimize computation. We never meant to do dataflow, it just forced itself on us. 🙂

kennytilton01:07:13

OK, yes, Reagent is susceptible to glitches, meaning with just the right set up of ratoms a change to one will propagate twice to a ratom, with the first calculation being inconsistent with the original change. I imagine re-frame inherits this edge case.

mikerod01:07:16

Would be good to have a simple example to check it out

mikerod01:07:11

Re-frame primarily (only?) uses reactions though I believe.

mikerod01:07:33

So if it is specific to ratom, may not be the same there.

mikerod01:07:11

Could be wrong too. Well I guess app state is in a ratom actually. Will have to look around

kennytilton01:07:04

(def xx (r/atom 0))
(declare bb)
(def zz (r/track! #(let [r (if (> @xx 3)
                             (+ @xx @bb)
                             @xx)]
                     (prn :zz r)
                     r)))
(def aa (r/track! #(do (prn :aa)
                       (* 10 @xx))))
(def bb (r/track! #(do (prn :bb)
                       (* 10 @aa))))

4
kennytilton01:07:16

Now increment xx until it gets to 4 and you will see zz take on first 304 and then 404.

kennytilton01:07:21

Changing xx marks zz and aa as dirty, but does not mark bb as dirty. xx notifies zz first and it runs and gets a now obsolete copy of bb. xx then notifies aa who notifies bb who then re-notifies zz.

kennytilton01:07:36

xx cannot be sure bb is dirty because aa might not change. MobX has two dirty states, definitely and possibly, which here would be applied to aa and bb.

mikerod01:07:49

Interesting. Will check this out soon.

kennytilton01:07:58

The trick MobX and my hack both use is to make one last check when deref-ing that the value being grabbed is current.

kennytilton01:07:36

btw, having the dependency on bb conditional is not (I think!) necessary to expose the glitch. It is there just to defeat naive solutions as “check all your dependencies before running”. Since zz does not yet know it will branch to a read of bb that will not surface the problem. That is why MobX and I check for currency as the actual read of any ratom is executing.

kennytilton10:07:09

And regarding #re-frame, using reg-sub for zz would mean listing bb in the signals, because it might be needed. This avoids the glitch at the expense of recomputing zz unnecessarily when bb changes and xx is <= 3. So reg-sub-raw is misnomer; reg-sub is not syntactic sugar, it is a different animal.

👍 4
justinlee18:07:20

the experiment above shows that what i’m seeing should not be possible

mikerod18:07:33

it’s a bit of a mind-twist to go through the reaction logic

mikerod18:07:53

I’ve done repl-time modifications in it before to gather more contextual info before to troubleshoot things

mikerod18:07:57

it’s a deep dive though

kennytilton22:07:03

@lee.justin.m As a long-time reactionary I can tell you that (a) it is wonderful something-for-nothing magic but (b) if you exercise it hard enough you will run into what we can call (nom du jeur) “lifecycle”. As in, “Jeez, when does this fire?” I just did some experiments with re-frame (yes, experiments are a great way to sort these things out) and what I saw was that re-frame is too simplistic to get into much confusion, at the cost of over-propagation. (But that over-propagation is rarely a problem in practice.) I stopped experimenting before I got to reagent but if you would like to share your use case I will be happy to take a look. If you are really curious about the paradigm, scroll down to “data integrity” here to see the guarantees we need for reactive software: http://smuglispweeny.blogspot.com/2008/02/cells-manifesto.html

justinlee22:07:43

thanks @hiskennyness. i actually figured out the problem. I was seeing concurrent networks calls and wondering how it was happening. it was happening because… I was making concurrent network calls lol

justinlee22:07:09

i thought it was happening because state changes were happening out of order

justinlee22:07:44

but reagent does not ever appear to cause re-renders on state changes synchronously, which is a good thing

kennytilton22:07:45

OMG! Concurrent network calls are the last thing I worry about when I am making concurrent….hang on…

kennytilton22:07:51

Glad to hear your world is right again, God is in his heaven, and all that…

kennytilton01:07:13

OK, yes, Reagent is susceptible to glitches, meaning with just the right set up of ratoms a change to one will propagate twice to a ratom, with the first calculation being inconsistent with the original change. I imagine re-frame inherits this edge case.

kennytilton10:07:09

And regarding #re-frame, using reg-sub for zz would mean listing bb in the signals, because it might be needed. This avoids the glitch at the expense of recomputing zz unnecessarily when bb changes and xx is <= 3. So reg-sub-raw is misnomer; reg-sub is not syntactic sugar, it is a different animal.

👍 4