The model they've chosen is the opposite of what one would intuit and because of this model, it is necessary to manage state a bit differently in React compared to Vue or Svelte.
This is genuine question; I've not used Vue or Svelte.
Vue and Svelte don't work that way.
In a Vue SFC, this is fine:
<script setup>
let counter = 0 <-- This code only runs once
watch (someRef, () => { <-- Only this code runs when someRef changes
counter++
console.log(counter)
})
const fn = () => { ... } <-- Normal functions are stable
function fn2 () { ... } <-- Stable as well
</script>
Basically, it behaves like you would expect normal JS closures to behave because the `setup` function is invoked only once. When `someRef` changes, only the `watch` function is executed (this is also why Vue and Svelte perform better because they can execute a smaller subset of code on updates).JS and DOM itself work with the same conceptual model, right?
<button onclick="handler()">...</button>
<script>
let counter = 0 <-- Allocated once
function handler() { } <-- Only this code is executed
const fn = () => { ... } <-- Allocated once
</script>
In React, this (obviously trivial example) doesn't work: export const App = () => {
let counter = 0 <-- New allocation on each render
const fn = () => { ... } <-- New allocation on each render
// ...
}
Because the entire `App()` function gets invoked again. So you have to use hooks to move state out of the path of the component function because the entire component function is re-invoked. Imagine if React, instead of invoking the entire `App()` function, only invoked the code affected by the change as captured in the dependency array. That's how Vue and Svelte work; the same way that a handler function via `addEventListener()` only executes the designated handler function. React does not work this way. Think hard about that and how React is conceptually opposite of how events work in DOM itself.This difference in design means that in Vue, there is -- in practice -- almost never a need to do manual memoization and never really a thought of "where should I put this"?
It might seem obvious here, right? if `fn` has no dependencies on the component state, then it can just be moved out of the `App()` function. But this is a common mistake and it ends up with excess stack allocations (also why React is generally the poorest performer when it comes to memory usage).
React's model is a bit of an outlier for UIs which generally assume state encapsulated by a component is stable. React says "no, the component function is going to be invoked on every change so you cannot have state in the component."
A different way to think about this is to go look at game engines or desktop UI frameworks which render stateful objects onto a canvas and see how many game engines or UI engines assume that your object is recreated each time. This is certainly true of the underlying render buffer of the graphics card, right? But generally the developer builds on top of stateful abstractions. React has, in fact, moved the complexity onto the developer to properly place and manage state (while not being faster nor more memory efficient than Vue or Svelte).
I believe that a lot of React's expanding complexity flows from this design decision to model inherently stateful UIs in a "pretend everything is a stateless function" way because it is fundamentally playing opposite day against the underlying JavaScript and DOM.
Another thing I found un-intuitive with React is the state of multiple instances of the same component. The useState() hook basically references some global state in the global context. When the component is used in multiple places, i.e. <my-comp></my-comp> <my-comp></my-comp>, the useState() hook inside is called twice and somehow they get a different copy of the global state. I know the magic of the global array to track the states. It just feels a bit too magically.
I chuckle it's claimed that React component is functional. And cringe whenever people put out the UI=F(props) statement, as if calling F with the same props multiple times getting a different set of state values not the anti-thesis of being functional.
https://news.ycombinator.com/item?id=37349286
great explanations, thanks!