3 ms·
I, for one, would intuit that exact process flow. If my UI is a function of my state, I expect state changes to re-render my UI. How else would you handle it, e
by WesleyJohnson 2y ago
I, for one, would intuit that exact process flow. If my UI is a function of my state, I expect state changes to re-render my UI. How else would you handle it, except for imperatively?
This is genuine question; I've not used Vue or Svelte.
- CharlieDigital 2y agoIt re-invokes the entire render function of the component so that the state in the component (meaning not externalized to a hook or declared outside of the component) is effectively wiped out. 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.
- mpawelski 2y agolol, I added this comment to favorites remembering I once did add some other comment explaining well some React rendering behavior pitfalls, and it looks it was you too :D https://news.ycombinator.com/item?id=37349286 https://news.ycombinator.com/item?id=37349286 great explanations, thanks!
- WesleyJohnson 2y agoI know this is a few days old, but I appreciate the excellent response and explanation of the differences. I still love React, but that's likely bred out of familiarity. I'll have to look at some of these other libs/frameworks to see what I've been missing.
- ww520 2y agoThanks for the detail explanation. That's what I understand how React works. 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.
- breadwinner 2y agoReact is definitely not functional, see https://mckoder.medium.com/why-react-is-not-functional-b1ed12a41323 https://mckoder.medium.com/why-react-is-not-functional-b1ed1...
- the_gipsy 2y agoIf rendering or not can change the state, then your UI is not a function of your state.