Forum Moderators: open

Message Too Old, No Replies

An illustration of why I don't really understand reactive frameworks

Seriously, what do they bring to the table...?

         

ronin

11:49 am on Oct 1, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



There are no small number of clear-thinking, clever people who use React (and frameworks like React: Preact, Solid.js etc.), so, before I get going... I recognise it's me who is the odd one out here.

Nevertheless, this morning I came across something which reminded me explicitly that the main reason I don't use React is not because beyond several false starts a couple of years ago I've never set aside the time to learn it (though there's enough other things to learn that I haven't) and it's not because I'm afraid that it's so complex I could never get my head around it (I've spent enough time now in the trenches with JavaScript that I'm sure if I properly applied myself, I eventually could).

It's that every time I see React being used and understand how it's being used, I start to question the need for it.

Dan Abramov is a very smart guy, .

Along with Andrew Clark, he co-authored Redux, which I have zero familiarity with, but it's really well known as the first major successor to Facebook's Flux architecture - and is described by Wikipedia as:

a library for managing and centralizing application state. It is most commonly used with libraries such as React or Angular for building user interfaces.


So I paid attention when I randomly came across this blog post from Abramov this morning (led there from a ycombinator thread about Solid.js and how it compares to React with classes, React with hooks etc. - yes, I don't have a grounded understanding of any of these JS-based technologies - I'm reading way beyond my comfort zone, but it's important that I try because I'm a long way into building an approach for markup-based declarative full-stack components to be distributed across web3 and I want / need to be aware of what issues other architects have encountered / negotiated / solved before me):

Making setInterval Declarative with React Hooks
[overreacted.io...]

So, here we go. In the course of the blog post, Abramov writes a React hook:

useInterval()


which looks very similar to VanillaJS:

setInterval()


Anticipating the reader's question:

So why not just use setInterval directly?


He responds:

This may not be obvious at first, but the difference between the setInterval you know and my useInterval Hook is that its arguments are “dynamic”.


And then he proves it with an example.

"Great!" I thought. "I suppose you'd need a reactive framework like React to easily put together an example like that. I'd bet that in VanillaJS it takes tons and tons of code!"

I 'd read enough and I was satisfied. Before I could draw a line and turn my attention to something else, I became aware that the engineering part of my brain had heard my last thought and interpreted it as a challenge.

Before I knew it, I was rolling up my sleeves to find out just how much code it would take in VanillaJS. I still thought it would be a lot - possibly so much that I would quit halfway through my investigation, satisfied (properly this time) that there really are some things you can code elegantly, efficiently and concisely in React which outclass a more conventional, vanilla approach in every way.

Anyway, to my surprise as much as anyone else's, I had my answer about eight minutes later:


<h2 class="counterHeading">0</h2>
<input class="intervalInput" type="text" value="600" />



const counterHeading = document.querySelector('.counterHeading');
let counterIntervalInput = document.querySelector('.intervalInput');

const getCounterInterval = () => counterIntervalInput.value;
const getCounterValue = () => parseInt(counterHeading.textContent);
const incrementCounterValue = () => counterHeading.textContent = (getCounterValue() + 1);

let incrementCounter = setInterval(() => incrementCounterValue(), getCounterInterval());

const updateCounterInterval = () => {
clearInterval(incrementCounter);
incrementCounter = setInterval(() => incrementCounterValue(), getCounterInterval());
}

counterIntervalInput.addEventListener('change', updateCounterInterval);


Ten lines. It takes just ten lines of JavaScript (and two lines of HTML).

The code above is (as far as I can tell - and I'm more than happy to be corrected) robust, reusable, and closer to the metal than React. It's readable, it's short - it's definitely not mind-numbingly complex. It is (I would argue) easy to reason about.

And now, having briefly satisfied myself that there was value in React after all (even if I don't know it and don't use it), I'm now completely confused again.

What is the point of reactive frameworks like React?

If anyone has some enlightening words, I am all ears.

ronin

8:50 am on Oct 2, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Recently I've started to learn HTML5 Canvas.

(I do my best to make a start learning - even if I start very slowly - one new web-related syntax / domain specific language every year - I've not got very far with TypeScript (2018) and Deno (2020) and even less far with Vue (2019) and NativeScript (2021) so, to give myself some much-needed catch-up time, I thought I might go for something which is, hopefully, a bit less ambitious in 2022...)

HTML5 Canvas has introduced me to the concepts of Immediate Mode and Retained Mode, which I'd never come across before.

Essentially, graphics on the Canvas are like a flipbook animation.

In contrast to the kind of transitions and animations that you see in HTML + CSS and / or SVG, where known lines and shapes are transformed from their currently-known positions to new positions, HTML Canvas graphics aren't recorded, aren't stored, aren't remembered in any way. Instead the entire canvas is simply re-drawn from scratch on every animation frame (hence my flipbook animation analogy above).

You'd be forgiven for thinking that re-drawing the entire canvas from scratch every time is slower - that's certainly what I would have expected - but, apparently, because nothing is stored, nothing is kept in memory, (and it seems that writing to memory is one of the things that can slow animated graphics down) it's incredibly fast.

One of the big things about React (if I've understood correctly) is that on each User Interaction, after using the Virtual Dom (vDOM) to calculate the new positions / presentation of actual DOM nodes, the entire DOM is re-rendered from scratch (is that right?)

So... if that's all correct, does React essentially aspire to the sort-of-equivalent of an immediate mode DOM as opposed to the conventional retained mode DOM?

Is that, ultimately, underneath all the marketing fluff, the radical departure that React represents?

If it is, I suppose that fits with React's claim that it represents a declarative approach, in which it, essentially, declares (or re-declares) the entire DOM following each user-interaction.

Even though code like:


const { render } = ReactDOM;

const Welcome = () => (
<div id="welcome">
<h1>Hello World</h1>
</div>
);

root.render(<Welcome />);


has never looked to me like it's that declarative.

If it were simply:


<Welcome />


I'd find it easier to accept the claim.

ronin

10:33 am on Oct 4, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



There's a great comment in this thread:

[news.ycombinator.com...]

which confirms something I've always suspected about React and React-like frameworks / libraries.

Whenever people used to say things like "DOM is slow" and "Virtual DOM is faster than DOM" - something about that never rang quite true for me. I felt like there must be something they were not saying.

Something like: "DOM is slow when you're going about things using Approach Y. So when going about things using Approach Y, it's faster to use vDOM."

But deliberately omitting to mention that Approach X (ie. conventional JS + DOM) is also available and, not only is it massively faster than Approach Y + DOM, it's also marginally faster than ApproachY + vDOM.

This poster nails it:

Instead of building creating and update logic, you just need creation logic and always rebuild the widget. But that's super slow, so you use a virtual DOM to make it faster. Just not as fast as it would have been if you hadn't used the framework.

ronin

1:45 pm on Oct 6, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I did refer to reactive frameworks in the title of this thread, so I don't want my comments here to come across like I'm picking on React, exclusively, when actually my comments refer to the whole genre.

A while back I decided I really ought to learn at least one modern JS reactive framework. That was going to be AngularJS (in 2015), then React (in 2017), then Vue 2 (in 2018).

I made one or two abortive starts on Vue 2 in 2018. I never got very far before other calls on my time interrupted my focus. I needed to get my head down, so I resolved that 2019 would definitely, definitely be the year I started learning Vue.

[...]

In late 2020, a new, rewritten version of Vue launched. I still hadn't got started on Vue 2, so this felt like the nudge I needed. I committed to focusing on Vue 3 as the modern JS reactive framework in which I would learn to write reactive Single Page Apps (SPAs).

In Nov 2022, I've set aside some time and I'm finally learning Vue 3.

Only a short way into my first course video (02:20), the teacher references Vue's reactivity, remarking:

And notice how short and sweet it is. Compare that to,using vanilla javascript, or even jquery, to do the same thing.


What are we comparing?

This in Vue 3:


<script setup>
import { ref } from 'vue'

const msg = ref('Hello World!')
</script>

<template>
<h1>{{ msg }}</h1>
<input v-model="msg">
</template>


Agreed. That is quite short and sweet.

And what's the VanillaJS we're comparing to it?


<h1>Hello World!</h1>
<input type="text" />

<script>
const myHeading = document.querySelector('h1');
const myInput = document.querySelector('input');

myInput.setAttribute('value', myHeading.textContent);
myInput.addEventListener('keyup', () => {myHeading.textContent = myInput.value});
</script>


That's it. Four lines of VanillaJS. If I was being careless, I could even omit the two node references at the top and then it would only be two lines.

So what's with the:

Compare that to,using vanilla javascript [...] to do the same thing.


Yes, you need to know the keyup event. Is that it? Really?!?

I can't be the only one who reads this sort of thing and thinks that the hype on reactive frameworks is sometimes a bit overblown?

It's not that I've made up my mind custom-syntax reactive frameworks are a complete waste of time - I wouldn't be committing to learning Vue 3 if I thought that.

But it's - I'd argue - not reasonable for any framework to intimate that VanillaJS is obscure or convoluted or verbose, when it clearly isn't.

ronin

9:21 pm on Oct 6, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Ohhh. I finally get it.

I've been doing some more - a lot more - reading around the subject.

What is the point of reactive frameworks [...] ?


It's not about the reactivity, per se.

The front-end framework-based reactivity in React, Vue etc. is the mechanism which keeps multiple dimensions of state continuously up to date across multiple components.

But the key concept here is not the mechanism... it's the maintenance of complex state.

Now I've realised that - and it feels like quite a big epiphany - I can properly compare reactive frameworks to VanillaJS (a comparison which can inform my continuing development of web3-distributed markup-based declarative full-stack components).

And by "properly", I mean not comparing lines of code and reflecting on how elegant / concise / self-explanatory they are (as I've been doing above) but comparing how performant / responsive a complex-persistent-state VanillaJS MPA can be, next to a complex-persistent-state Reactive Framework SPA.

Lexur

7:35 am on Oct 7, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Ohhh. I finally get it.


I'm glad I was helpful being here while your brain almost exploded, and that you found the answer in that complex state maintenance, whatever that is, because I have no idea about programming.

Is there anything else I can do for you? &#128515;

tangor

7:28 pm on Oct 7, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I love it when an internal conversation culminates in a fruitful result!

Talking to oneself is part of the learning process.

ronin

9:43 pm on Oct 7, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I love it when an internal conversation culminates in a fruitful result!


Indeed!

See:

Rubber Duck Debugging
[en.wikipedia.org...]

tangor

1:20 am on Oct 8, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Heh! Learned more arguing with myself on new topics/knowledge than ever learned from "teachers"... and walked away with more confidence. Especially when I had that "light bulb!" moment. :)