Fork me on GitHub
#reagent
<
2018-07-19
>
milomord15:07:39

I think Redux/Flux-like architecture is a nice way of managing state because it's a very clear way of managing state. Have also been using MobX recently on a new project so we will see how that grows.

milomord15:07:34

Though this is a Clojure forum so I won't talk about MobX too much. I have also tried to use Hoplon in Clojure(script) land, but the HLisp stuff kind of rubs me the wrong way honestly

kennytilton15:07:31

I think as long as we are discussing state management MobX has to be in the mix. And we are discussing React rather prominently, which will not get converted to CLJS until v42 according to their roadmap. I made that up.

kennytilton15:07:43

Redux/Flux is clear from 30k feet and next thing you know we are watching 24 free videos and still struggling to do what we want to do. Productivity tools are supposed to save developer energy, not consume it.

kennytilton15:07:18

Hoplon is great, Matrix is great, binding.scala is great, but MobX is the dataflow mindshare leader. The CLJS community might want to choose carefully in this space.

justinlee15:07:38

have you ever built anything with MobX? very tricky to get right. it is very hard to monitor arrays in javascript and requires coding by convention. reagent’s atom system blows mobx out of the water.

justinlee15:07:38

also, where did this ‘dataflow’ terminology come from. in my world, this is called the ‘observer pattern’ from the GoF book

milomord15:07:05

Have been using mobx-state-tree/mobx recently and not sure how I feel about it yet. The main positive aspect so far seems to be a lot less boiler plate/things getting in my way. My main concern with it is readability as the code base gets larger + being able to debug/test it (Redux is so easy to debug/test).

milomord15:07:45

Reagent + ratom remains kind of a personal favourite, Re-frame isn't so bad but similar problems to Redux where I feel it gets in my way a lot

milomord15:07:01

Main problem for me is I can never sell Cljs to my team 😛

justinlee15:07:05

my memory of mobx is that you can’t observe a blank portion of the state. you can do that with ratoms. i.e. you can create a cursor to something that isn’t there and then you get a re-render when it loads. stuff like that just works better because mobx is kind of a filthy (but awesome) hack

milomord15:07:44

Ah, that may well be true

milomord15:07:03

I think that's the real heart of why ratoms are great, because they are really just a part of the language, they are very idiomatic

milomord15:07:16

MobX feels like it's really pushing JS, and it works really well!

milomord15:07:24

But at the end of the day it is a hack as you say

justinlee15:07:50

mobx is also synchronous, if i recall, which is kind of tricky to deal with if you’re not thinking carefully about whether a mutation might cause another mutation

justinlee15:07:12

it’s a miracle that mobx works at all 🙂

Hukka15:07:42

You could say the same about reagent 🙂

milomord15:07:44

This is true, and why mobx-state-tree/mobx in strict mode forces you to wrap state changes in actions

Hukka15:07:16

It's magic written in a language, that compiles to a language, that compiles to a language, that uses magic (react) and compiles to a language and...

milomord15:07:32

CLJS is magic, Reagent is just a nice library 😛

milomord15:07:02

React I think is more a little bloated than magic

Hukka15:07:19

Not to mention that the compilation happens on magic written on a language, that compiles to a language, that compiles to a language that...

justinlee15:07:40

the distinction for me is that I understand why reagent works: there’s a level of indirection that is built into cljs: specifically the fact that you can only manipulate atoms by derefing them. reagent inserts itself right there in that single place. mobx is doing screwball things to intercept direct object accesses and array manipulations.

milomord15:07:00

sure, Reagent definitely doesn't feel like magic if you know Clojure, it just feels like a natural way of doing things/a slight extension of what you know

milomord15:07:15

Then re-frame is just a pretty opinionated pattern on top of that core

milomord15:07:33

MobX I don't want to the look at the code because I think I'll have nightmares

🙂 4
milomord15:07:18

And I am surprised every time it works, especially in non-strict mode (which I think they have basically acknowledged was a bad idea, though it rules for prototyping)

justinlee15:07:34

to be clear: i’m a much stronger js programmer than cljs programmer still. my years of C++ are hard to shake 🙂

kennytilton16:07:13

If we are surveying the field we are at 30k feet, so I would not exclude any library from discussion over details. If MobX is insufficiently granular, fine. Does it offer anything on transparency? Hoplon/Javen is limited by the “lifting” mechanism. Fine, but is it too great on transparency? Re-frame has a beautifully clear domino thing. Does that mean explicitly coding subscriptions and events? There is no superficial way to explore this space.

justinlee16:07:48

ah well that’s the issue. i’m not at 30k feet. I’m building product. everything looks good at 30k feet. 🙂

kennytilton16:07:06

What are you using now?

kennytilton16:07:54

And will you use that forever because to survey the choices means stopping typing? 🙂 I understand!

kennytilton16:07:33

Reagent is great. Keep an eye out for the glitches if you ever see something that makes no sense.

milomord16:07:59

I am as we speak working on a Redux app but dreaming of Reagent

👍 4
justinlee16:07:15

i never said anything was excluded or that we shouldn’t talk about it. if i didn’t want to talk about it i wouldn’t be here. i’m interested to hear what milomord and anybody else who actually uses this stuff has to say

justinlee16:07:38

i’ve offered my thoughts as to why mobx is hard to use, which came from practical experience

kennytilton16:07:09

I started with React on a hefty exercise and in two widgets realized why Abramov did Reflux. Re-doing those two widgets with Redux told me how brilliant are the CLJS React wrappers.

kennytilton16:07:10

I am grateful for the input from a hardcore JSer on MobX. I just surfed the doc and took a deep dive into the internals to explore its solution to glitches, but a real user such as yourself offers great perspective.

milomord16:07:06

I am too early on in my Mobx/Mobx State Tree exploration to offer advice on practical drawbacks/pitfalls unfortunately, but very curious to see how it goes for me

lilactown16:07:42

FWIW, I have not yet used it in anger but it feels like React context + suspense attacks the same generic problem as Redux and Reagent (with ratoms) but in a much simpler way

milomord16:07:00

My experience of Reagent/ratoms has been 'joy to work with' pretty much, though it does give maybe too much freedom to me

justinlee16:07:22

@milomord be sure to read and understand https://mobx.js.org/best/react.html because you will be bitten by some of that unless you are careful to write code to avoid these pitfalls

lilactown16:07:41

esp. suspense I feel like is moving us towards shaking off the "only the V in MVC" lie that we've been using to sell people on React for awhile 😉

milomord16:07:47

Thanks @lee.justin.m, I have already stumbled upon this after being bitten!

milomord16:07:47

It will be interesting to see if people start using Suspense

milomord16:07:56

(outside of presumably FB)

kennytilton16:07:03

@milomord The True Lisper holds sacred the right to shoot off their own feet with too much freedom.

milomord16:07:16

But I am generally not thrilled with React's own solutions to state management so far

milomord16:07:49

I think they know this hence why they pushed people toward Flux/then Redux and obfuscated the context api somewhat

kennytilton16:07:57

damn, missed suspense — googling

milomord16:07:47

As I understand Suspense (not that well), it is more about waiting for network requests to complete

lilactown16:07:26

it's about any side effects, really

kennytilton16:07:31

The very best thing in the world is the React doc on context saying “no matter what you do, do not use context”.

lilactown16:07:06

AFAICT after 16.3 that's old advice. the new context API has been deemed production ready

lilactown16:07:30

the reason that they suggested not to use the old context API was because it was likely to change

milomord16:07:14

honestly I never liked the idea of context within React but I forgave it because it makes some things slightly easier (eg, routers/outside stores)

kennytilton16:07:17

There was a funny video where someone asked the Facebook team (at an open conference) about context and one of them turned to the others and said, “I told you they would find it.

milomord16:07:37

Haha, context is an escape hatch

lilactown16:07:58

most of the uses of state management libs have to do with 2 concerns: 1. plumbing state 2. reacting to side effects context addresses 1. suspense (begins to) address 2

kennytilton16:07:32

And apparently one we need, in turn a refutation by example of the whole idea of isolation. It’s all connected, spaketh Buddha.

milomord16:07:05

Thing is, I actually think I like React just being the view layer/a declarative view layer

kennytilton16:07:19

Yeah, and now I see they have some insanely elaborate “forward ref” thingy that let’s us get at the dom.

milomord16:07:55

And if FB are interested in turning it into a more fully fledged framework/standalone solution I will watch with interest but

kennytilton16:07:03

View and model are one. (Prepare the tar and feathers.)

milomord16:07:25

'View and model are one' such a lisper

lilactown16:07:13

I think that declarative and "just being the V" are orthogonal

kennytilton16:07:27

Actually, I lied. All my views have a value slot. For the model object.

lilactown16:07:53

e.g. graphQL + React is declarative, but also quite a bit more than just the V

kennytilton16:07:35

My guess? They spent three months trying to figure out state management, came up short, and decided to make the gaping whole a feature by bragging about how they were not telling us how to manage state. But we had to use Flux,

lilactown16:07:22

I think it's a feature that React has not implemented a lot of what has been filled in by other user-space libraries libs up until now

lilactown16:07:39

because you're right, they didn't know how to do it correctly. I don't know anyone who does

☝️ 4
justinlee16:07:07

if they’d implemented a state management library you’d be complaining that their solution isn’t composable and isolated

lilactown16:07:35

Flux, Redux, MobX, etc. are great experiments that the React team and community has learned a ton from

lilactown16:07:42

and we're starting to see the fruit bear in the form of new React APIs that address those concerns, but at the framework-level

kennytilton16:07:02

“I don’t know anyone who does.” raises-hand

lilactown16:07:05

well then show us the way, oh hiskennyness :rolling_on_the_floor_laughing:

kennytilton16:07:19

They are only making things worse, doubling down on more and more framework in knee jerk solutions to every problem the user community brings to them.

lilactown16:07:39

that is the opposite of what they're doing lol

lilactown16:07:04

if that had been the case then they would have integrated Flux, or Redux, into React

lilactown16:07:26

it's not a knee jerk reaction

kennytilton16:07:01

@lilactown I understand the skepticism! But I have been at this for 22 years so I am comfortable with the raised hand. See how far you get with this: https://codepen.io/kennytilton/pen/mXQNYR

kennytilton12:07:54

@lilactown did you miss this? You asked me to produce it and said I was full of shit, so I think that means you have to read the whole thing and do the exercise on frame 6 and blog about what you learned. 🤞

justinlee16:07:14

react has been around for 5 years. they’ve cleared 10,000 bugs! definitely not “knee-jerk”

justinlee16:07:00

facebook has ~50,000 react components in their own internal codebase. these guys are not shooting from the hip

kennytilton16:07:05

Redux was a failure. MobX — imperfections acknowledged! — has been eating its lunch with its transparency. Transparency being a buzzword for “we work out the dataflow, you just write the natural expression of your semantics”.

lilactown16:07:15

@hiskennyness I'm not questioning your experience. But I fundamentally think that anyone who claims they have the solution to designing and creating UI applications is full of shit

👆 8
kennytilton16:07:34

I’m not questioning your language skill, but I think you just questioned my experience. :rolling_on_the_floor_laughing:

lilactown16:07:28

I don't think we'll have a great solution in our lifetime

kennytilton16:07:48

For a second, @lee.justin.m, I thought you were describing CICS. 🙂

lilactown16:07:46

I've talked with Jordan Walke and other people who are involved in React / ReasonML and they are all incredibly intelligent, and humble enough to admit that they don't know a lot of answers. some of the questions we don't even know yet

kennytilton16:07:03

I will take that as a compliment, @lilactown

milomord16:07:34

I don't think there is a ‘the’ solution, everything has benefits and drawbacks

milomord16:07:46

At the end of the day something is good enough to build what I want to build

milomord16:07:58

And I'll learn from using it and move forward after that

👏 4
kennytilton16:07:03

Just look at the results. They are flailing. And yet they persist. Do you know what it looks like when smart engineers are not expereinced enough to realize they have done bad work?

milomord16:07:15

I mean, I don't think Facebook is 'failing' to serve applications to their users

kennytilton16:07:59

See “StoneHenge”. Or Ivan Sutherland doing a CAD system in assembler in 1963 with nothing but a light pen that “read” the 1024x1024 CRT screen. The question is, what was the wasted effort using a deficient UI?

kennytilton16:07:56

What if there is a “the solution”? Would that be a problem in that it violates our meta-certainty of what is possible? Long before Paris the editor of a beekeepers journal saw the Wright brothers flying around a field outside Daytona. He wrote to the Smithsonian to say OMG! The Smithsonian wrote back to say it was impossible, if anyone could fly like that it would have been in the papers. That only cost them a stamp.

kennytilton17:07:25

Getting back to Suspense, here is a funny story about how dataflow handles Callback Hell without missing a beat (surprised even me): https://github.com/kennytilton/xhr/blob/master/cljs/xhr/XHR.md

samueldev17:07:35

CBH isn't even really a thing in native js now with async/await, fwiw.

jthibaudeau17:07:05

Has anyone come across reagent not re-rendering when the sort order of a subscribed to sorted-map changes? I am guessing it is doing (= sort-map-asc sort-map-desc) when checking props and that returns true whereas (identical? sort-map-asc sort-map-desc) would return false causing a re-render but I am not 100% sure

kennytilton18:07:43

Pardon a dumb question, but how does the sort order of a sorted-map change? Do you mean sorted-map-by? But I think your guess is right about = being true will get in the way of reagent detecting the change.

jthibaudeau18:07:09

Yeah, an event will change the sort order of the map and the subscription will use sorted-map-by to return the sorted map

kennytilton18:07:10

Hmm, in a repl I just got

`(= (sorted-map-by < :a 2 :b 3) (sorted-map-by :b 3 :a 2)) => false
Oops, forgot the comparator…

kennytilton18:07:43

This is better:

`(= (sorted-map-by < :a 2 :b 3) (sorted-map-by > :b 3 :a 2)) => true
`

justinlee18:07:23

@jamesthibaudeau i think your diagnosis is correct: because sorted maps with different comparators are =, reagent will not re-render

kennytilton18:07:41

Ooops: “For ratoms, identical? is used (on the value inside the ratom) to determine if a new value has changed with regard to an old value.”

kennytilton18:07:56

“For props, = is used to determine if a new value have changed with regard to an old value.” (from the same link)

kennytilton18:07:23

Make sure, of course, that you are dereferencing the ratom. The ratom remains identical?

justinlee19:07:18

Confirmed:

(def sorted-state (reagent/atom (sorted-map-by < [0 "zero" 1 "one"])))

(defn child-component
  [s]
  (js/console.log "child-component")
  [:div (pr-str s)])

(defn test-component
  []
  (js/console.log "test-component")
  [child-component @sorted-state])

(js/setTimeout (fn []
                 (js/console.log "updating comparator")
                 (reset! sorted-state (sorted-map-by > [0 "zero" 1 "one"])))
               1)
prints
test-component
child-component
updating comparator
test-component

justinlee19:07:18

if you change the reset to (reset! sorted-state @sorted-state) then the second test-component doesn’t print

kennytilton19:07:36

sorted-map-by wants its keyvals as &rest args, right?

jthibaudeau19:07:42

[comparator & keyvals]

justinlee19:07:17

yea, though it is irrelevant 🙂

justinlee19:07:21

you get the same results

justinlee19:07:54

the only thing that matters is that sorted-map is = with different comparators, and when passing props, reagent performs an = check

justinlee19:07:06

when choosing when to notify watchers, it uses identical?

jthibaudeau19:07:06

what I think I will do is have my subscription return {:order :asc :data sorted-map-asc} or the corresponding desc version

jthibaudeau19:07:27

have reagent check the equality on that map instead of the sorted map itself

justinlee19:07:44

you can probably do something with protocols / types such that you have a version of sorted map that has different = semantics but being explicit is probably better

jthibaudeau19:07:42

yeah, could do it that way too, thanks for your help guys!

Bravi22:07:53

is there a different approach to scroll event handler in reagent? all the other events seem to fire, except this one:

(r/create-class
     {:component-will-mount
      (fn []
        (.addEventListener js/window "scroll" #(js/console.log "hello")))
     ...
    })

Bravi22:07:33

if I change that to resize, it works

kennytilton12:07:54

@lilactown did you miss this? You asked me to produce it and said I was full of shit, so I think that means you have to read the whole thing and do the exercise on frame 6 and blog about what you learned. 🤞