DEV Community

Cover image for How React isn't reactive, and why you shouldn't care

How React isn't reactive, and why you shouldn't care

Ryan Carniato on March 18, 2021

If the title agrees with you, you can stop reading right now. Move on to the next article. In technology, we tend to grab on to differences to come...
Collapse
 
peerreynders profile image
peerreynders • Edited

Its most famous incarnation in JavaScript is RxJS ...

From the ReactiveX Introduction

It is sometimes called “functional reactive programming” but this is a misnomer. ReactiveX may be functional, and it may be reactive, but “functional reactive programming” is a different animal. One main point of difference is that functional reactive programming operates on values that change continuously over time, while ReactiveX operates on discrete values that are emitted over time. (See Conal Elliott’s work for more-precise information on functional reactive programming.)

Essentially ReactveX ceded the "FRP" (Functional Reactive Programming) moniker to Conal Elliot's work stating:

(Reactive Programming + Functional Programming) !== Functional Reactive Programming

Back in 2014 - Comment

UPDATE: there's been a lot of confusion around the terms Functional Reactive Programming and Reactive Programming [1] [2].

Sorry, my bad. I guess this sort of confusion happens easily with new paradigms in computing.
Replace all the occurrences of "FRP" with "RP" in the tutorial. Functional Reactive Programming is a variant of Reactive Programming that follows Functional Programming principles such as referential transparency, and seeks to be purely functional. Other people are better at explaining this than I am. [3] [4] [5]

Collapse
 
ryansolid profile image
Ryan Carniato

I see.. I read Staltz' articles but missed his correction. I see I'm a victim of the same confusion. So FRP is yet a different concept. In some ways though this only continues to add to the confusion here. I don't even know what to name it then.. In JS we tend to mainly have the 2 forms Rx and Fine-grained (I've also heard it called SRP). Mind you that description makes FRP sound more like what I've been calling fine-grained.

Someone in academia will probably have to correct us. This has propagated to the point there is even some ambiguity in later white papers. Most of the language I use I reference from this paper on Elm: elm-lang.org/assets/papers/concurr...

But admittedly I'm a little grey where the exact distinction lies. Which is really the heart of the problem here. Calling out reactive or not is more about marketing than anything else.

Collapse
 
peerreynders profile image
peerreynders • Edited

With xstream Staltz converged on the term "reactive streams". And while I personally like "Rx" it's likely going to be associated with ReactiveX specifically or worse constantly have people quip about "medical prescriptions".
Conal Elliot actually stated this about Elm:

I may have said that Elm was an offshoot of E-FRP iiuc. Sort of inspired-by-inspired-by-FRP.

A Survey of Functional Reactive Programming (2013)

Once signals were dropped in Elm 0.17 (May 2016) that discussion simply faded.


OK that is what this is about!

Truly reactive

No more complex state management libraries — Svelte brings reactivity to JavaScript itself.

Yes, there is a case here that the terminology is imprecise and perhaps even sloppy for the purpose of hype and marketing.

Unfortunately for the target audience "reactive" expresses exactly the message that Svelte wants to convey - "change propagation analogous to that perceived with spreadsheet cell formulas" on the language level - right in your Java(Svelte)Script (which reminds me of Simon Peyton Jones referring to Excel as The world's most popular functional langauge).

But Svelte's difference isn't due to reactivity but because its compiler separates create/update paths allowing skipping on a VDOM.

This description is far more accurate - but it's my sense that in terms of a DX-obsessed audience it's just not as catching to accuse React of doing too much work at run-time when it could be doing it much more effectively at compile time.

So I guess Svelte's claim to reactivity is just as valid as React's claim that it isn't a framework (sorry, it is).

Thread Thread
 
ryansolid profile image
Ryan Carniato

Yeah exactly my point and thanks for digging a bit more. I'm going to edit the terminology in the article. It was my mistake for taking the FRP thing at face value. I will stick with our JavaScript made up terms rather than academic ones to avoid further confusion. I'm having a similar discussion on reddit where someone was really put off by me calling Rx FRP and even calling these different things. In JavaScript there are really 2 different types that have developed out but they are only small part of the spectrum.

I believe it is:
Reactive Streams - Asynchronous Events in continuous time
Fine Grained - Synchronous Behaviors in discrete time

But realistically you can have different combinations of these I suppose.

Thread Thread
 
trusktr profile image
Joe Pea

Qt's used-to-be-fine-grained reactivity just went from sync to async in a major version bump. Naming aside, I still look at it as the same thing, just everything is batched now.

Thread Thread
 
ryansolid profile image
Ryan Carniato

I've continued this line of thought over to a follow-up article: dev.to/ryansolid/what-the-hell-is-...

Collapse
 
brucou profile image
brucou • Edited

I like those argumented considerations! I have my own definition of reactive programming and functional reactive programming, but I can't agree more on the fact that we have to prioritize solving actual problems vs. debating the language. At the same time, in places where language do matter, we also have to give precise definitions, else we can talk past another for ages. And it does not matter if my definition is not yours, as long as I can precisely state mine and get understood when it matters.
If I may just add two considerations (that also matter very little), reactive systems change behaviors ONLY as a result of events (sometimes they call that stimuli). That means that if a reactive system does nothing, and receives no events, it continues to do nothing. Also there is an expectation that the reactive system keeps listening on events for processing. That is, there is a notion of liveliness: if something happens, the reactive system will react to it (eventually). I guess that is not really a point that will surprise anybody, but it is seldom mentioned and yet it is at the core of what a reactive system is --- if you remove any of these two things, you can still call your system a reactive one (and it still does not matter) but it becomes confusing.

Collapse
 
ryansolid profile image
Ryan Carniato

Yeah probably a better way of saying what I was trying to about data centric event emitters. And really my point about React not sitting there polling. Even if it is scheduled it only does so because of a data change event. React does nothing once settled if nothing calls setState.

Don't get me wrong. I am not saying definitions around Reactivity don't matter, or that I like misappropriation. More that by almost any criteria you would consider a modern UI framework reactive, React is as well. There is a really narrow slice where the argument could be made but it is splitting hairs.

I think the characteristics around events you describe are essential. The system needs to be driven off events over time. Sidestep events or "over time" and it isn't really reactive. But I'm open to hearing other opinions here. Just the Wikipedia definition is almost useless.

Collapse
 
brucou profile image
brucou • Edited

Fair enough. The same words may mean different things in different contexts so always good to take a tour of the landscape. IBM calls reactive systems systems that follow the reactive manifesto: reactivemanifesto.org/

Quoting:

We believe that a coherent approach to systems architecture is needed, and we believe that all necessary aspects are already recognised individually: we want systems that are Responsive, Resilient, Elastic and Message Driven. We call these Reactive Systems.

So if you talk about reactive systems to a systems architect, that is likely to be what he will understand.

If you look at academia, it is closer to what I mention, i.e. a system that continously react to external stimuli. quoting ce.pdn.ac.lk/research/complex-reac...

For these complex reactive systems, which continuously react to external stimuli (called events), we need methods and tools that permit specifying them in a precise, easy and safe way,

or here: ercim-news.ercim.eu/en67/special-t...

Many embedded systems belong to the class of reactive systems, which continuously react to inputs from the environment by generating corresponding outputs.

There is like a thousands of the same definition in papers as those folks must agree on the meaning of words before they even start to write research.

Then if you talk to web developers they will understand something else. Then how you define reactive programming is going to depend on how you define reactive systems.

When I said it does not matter, what I really mean is what matters is that you get understood, whatever words you choose to carry your meaning.

Thread Thread
 
peerreynders profile image
peerreynders • Edited

Then if you talk to web developers they will understand something else.

In my estimation that is what Svelte is talking about when it uses the term "reactive". It takes the perspective of the "developer as a user" differentiating between "explicit change propagation" (e.g. setState()) vs. "implicit change propagation" (i.e. "reactive"). From the developer perspective Svelte has two "reactive" systems:

Example: Reactive declaration

const schedule = (delay, fn) => self.setTimeout(fn, delay);

let a = 5;

// non-reactive declaration
let b = a + 3;

// "reactive" declaration
$: bR = a + 3;

console.log(bR === 8);

schedule(100, () => {
  a += 2;
});

schedule(200, () => {
  console.log(a === 7);
  console.log(b === 8);
  console.log(bR === 10);
}); 
Enter fullscreen mode Exit fullscreen mode

So through a little syntax sugar blocks of code can become "reactive - just like you're used to from spreadsheets".
The primary appeal here is that reactivity is gained with very little adjustment of the imperative mindset of managing the flow of control - except that now reactive code automatically stays in sync with its dependencies without any explicit change propagation.
This seems to be the reactivity that most of Svelte's buzz revolves around while the "developer as a user" persona cares very little how it's implemented under the hood.

Example: Stores

import { tick } from 'svelte';
import { derived, readable, get } from 'svelte/store';

const schedule = (delay, fn) => self.setTimeout(fn, delay);

let a = readable(null, set => {
  let value = 5;
  set(value);

  schedule(100, () => {
    value += 2;
    set(value);
  });
});

// non-reactive use
// Note use of `get()` is discouraged - used for demonstration only
let b = get(a) + 3;

// "reactive" use
let bR = derived(a, $a => {
  const value = $a + 3;
  return value;
});

// use reactive declarations to use auto-subscriptions
$: aLast = $a;
$: bRlast = $bR;

tick().then(() => {
  console.log(bRlast === 8);
});

schedule(200, () => {
  console.log(aLast === 7);
  console.log(b === 8);
  console.log(bRlast === 10);
});
Enter fullscreen mode Exit fullscreen mode

Stores require a bit more explicit setup though auto-subscriptions are supposed to make consuming them more convenient. However propagation of change at the source store has to be explicitly managed by developer code - so this requires a departure from the usual "imperative flow of control" coding.

Example: Stores with explicitly managed subscriptions

import { onDestroy } from 'svelte';
import { readable } from 'svelte/store';

const schedule = (delay, fn) => self.setTimeout(fn, delay);

let a = 5;
const aStore = readable(null, set => {
  set(a);
  schedule(100, () => {
    a += 2;
    set(a);
  });
});

// non-reactive
let b = a + 3;

// "reactive" subscription
let bR;
const unsubscribe = aStore.subscribe(value => {
  bR = value + 3;
});

console.log(bR === 8);

schedule(200, () => {
  console.log(a === 7);
  console.log(b === 8);
  console.log(bR === 10);
});

onDestroy(unsubscribe);
Enter fullscreen mode Exit fullscreen mode

Without auto-subscriptions consumers have to explicitly subscribe (and unsubscribe) to stores so we're even further removed from the "imperative flow of control" model.

So stores are available for more complex use cases but would generally be judged as the least wieldy of the two options.

It's also my opinion that the adoption of RxJS was ultimately limited by the need to shift ones coding mindset away from manipulating the flow of control at runtime to writing code that largely scaffolds the transformation and routing of event streams that - once constructed - just work.

The advantage of Svelte's reactive declarations/statements is that such a shift in mindset simply isn't required - it reminds me of how the majority of developers seem to prefer using async/await (maintaining the illusion of synchronous execution) over raw Promises.

Collapse
 
dodiameer profile image
Mohammed Ali Agha

In my opinion, the difference that sets apart Vue and Svelte from React is that you don't call setState in them, that is what makes them reactive.

React lets you take control and call setState when you feel like it, while Vue and Svelte abstract it away behind a runtime/compiler to give you a reactive feel

Collapse
 
ryansolid profile image
Ryan Carniato • Edited

I know a lot of people think that way. But that's just a syntax consideration. Reactive JavaScript libraries predate getter/setters and proxies. Like Knockout or earlier versions of Svelte, or countless other examples.

Does this hook make React any more or less reactive?

function useAssignableState(init) {
  const [state, setState] = useState(init);
  return {
    get value() { return state; }
    set value(v) { setState(v); }
  } 
}

// use like:
const count = useAssignableState(5);
count.value++:
Enter fullscreen mode Exit fullscreen mode

All of these do scheduling in the background depending on the library they are present in and are effectively identical:

setCount(5);

count(5);

count.set(5);

count = 5;

count.value = 5;
Enter fullscreen mode Exit fullscreen mode

Calling setState gives you no more or less guarantees than assigning a value in Svelte or Vue. It means that at minimum sometime in the future the state of your application will reflect this change. Calling setState 10 times or assigning 10 different values is all the same for the libraries we are talking about.

I respect syntax preferences and there are direct consequences to opting into single primitives versus the clear read/write segregation of React. But none of this has to do with reactivity.

Collapse
 
artydev profile image
artydev

Thanks Ryan
What do you think of Meiosis pattern?

Collapse
 
ryansolid profile image
Ryan Carniato

I think global stores are important and it has a solid foundation on FRP. It's homogenous all the way down which is important for any sort of scaling. The only real conflict (as always with these sort of things) is how much should be using the frameworks own primitives versus a 3rd party.

There is this thought that we can use this to make our code transferable. And it's sort of true but it is more just acknowledging Meiosis as the framework as you are invested in it. You might be able to move from React to Vue with it, but you are tied to Meiosis. This is true of any invasive state management approach (ie.. uses specialized primitives to propagate change)

Built-in primitives like Hooks, or other reactive APIs give the framework some places to optimize and offer unique features through their ability to manage orchestration. So that would be the only thing I'd caution on buying in too much on state specific solutions. It's probably fine in either case, but understand there are tradeoffs. When say React introduces concurrent rendering in SSR maybe Meiosis doesn't support that (not saying it doesn't, just hypothetical). That's the sort of consideration I think you have to make.

Collapse
 
artydev profile image
artydev

Thanks you very much for jour detailed answer

Collapse
 
goddard profile image
Ryein Goddard

Svelte looks to be a good option.

Collapse
 
ryansolid profile image
Ryan Carniato • Edited

For what? My point is that Svelte claim for Truly Reactivity vs React is basically a wash. Either they are both reactive or neither of them are by all but the narrowest (invented) criterion. So differentiating on that is mostly pointless outside of Svelte pointing out that they have built their primitives into the language instead of using an API.

Collapse
 
goddard profile image
Ryein Goddard

It just looks good. I like the simplicity. I always thought React was overly complicated and turns out I was right. Some projects start out with the best intentions, but it is easy to recognize a superior solution. I think one sad thing in web development is the stack is constantly changing. It is hard to really get a grasp on everything. That is probably the main reason people don't want to invest in Svelte as they already learned React which was a chore. At least that is how I would feel.

Thread Thread
 
ryansolid profile image
Ryan Carniato • Edited

Right but is the simplicity is any more real? Keep this in mind from someone who understand in depth how both the frameworks work (enough so that I could write an approximation of either from scratch). Once you peel back the layers not actually that different.

This works in Svelte's favor from an adoption side as since people are just starting to understand it is just as capable as React because I think people were hesitant not only because they are done learning, but because there was this preconception that it was somehow limited. Svelte is not limited in any sort of absolute way. Some problems require explicit not automatic solutions (like using Svelte stores). This fills the gap. Once you go there you can view Svelte's language feature more of an easy onboarding tool. It's a progressive learning thing. Once you get deep into it the biggest DX advantage of Svelte I feel is that the update model isn't convoluted, not some sort of perceived syntax benefit.

But obviously I have a bias I wrote Solid on the philosophy that React has it right by showing it's primitives and giving real control to the developer. Acknowledging the limits of compiled frameworks and taking no concessions from either side of the argument only the absolute power and performance. And I work on Marko pushing the limits of what a compiled framework can do. The choices Svelte has made are only too real.

Svelte does do somethings better than React and I actually think that it is really good at a lot of things people don't realize because of the pre-occupation with syntax. But most complexity in React is local scoped, and architecturally Svelte isn't really avoiding the complicated problems in any new way. Which is fine. I think what we are mostly seeing currently is that the size and scale of the average Svelte project is a lot smaller and we aren't hitting the same sort of problems yet. Then the solutions will come and the tradeoffs recognized.

React gets a bit of a bad rap at times, but the problems that come about in large/complicated systems go beyond the ability of any out of the box solution that comes with most minimal frameworks. These always need special consideration, and for now this almost blissfully naive ignorance will help Svelte gain the popularity it needs to get the support to attack these sort of problems. It takes time and the work of tons of people to get a framework ecosystem to where React is and Svelte has shown it is on the fast track. It is only a matter of time.

Collapse
 
steve8708 profile image
Steve Sewell

Amazing article, really great breakdown and read

Collapse
 
shriji profile image
Shriji

Svelte's syntax is simple.

Collapse
 
ryansolid profile image
Ryan Carniato

It definitely is.

Collapse
 
johnkazer profile image
John Kazer

There is a reasonable amount of literature around reactive programming using clojure and clojurescript. Which can use react too.