Hacker News new | past | comments | ask | show | jobs | submit login

I like the article, but it gets some things subtly wrong.

> To grossly oversimplify things: React assumes that your entire virtual DOM tree needs to be rebuilt from scratch, and the only way to prevent these updates is to implement useMemo

Not quite, on a state update, it rebuilds the component that was updated and all of its children. Not the entire virtual DOM; old versions of Angular did this, but it was wasteful.

useMemo doesn't prevent that, but React.memo can (useMemo has a different role; it lets you choose when to recompute or recreate a normal JavaScript object. But on its own it won't stop rerendering of child components!) [0]

This invalidates some of their assumptions. The reason why React isn't "push-only" isn't because it does that, it's because it sometimes buffers updates instead of always pushing them immediately. In fact, other frameworks like ~~Svelte also aren't "push-only" and hence not strictly reactive~~! [edit: this is no longer true after Svelte v5, see discussion below] (Funnily enough, OP uses an article as a source that explains this correctly [1], but it seems they took the wrong lesson from it).

The reason why signals are so cool is because the framework knows for any given state change which exact attributes in the DOM need to be re-rendered, even more specifically than "the element and all its children". But this neither implies reactivity nor the other way around. The two concepts are orthogonal.

Anyways, kudos to the author for diving into this so deeply!

[0] useMemo is useful in combination with React.memo sometimes, as the latter compares objects shallowly/by reference instead of their contents, so useMemo can be used to only recreate shallow references if its contents changed. You could probably also reimplement React.memo with useMemo, but you probably shouldn't. [1] https://dev.to/this-is-learning/how-react-isn-t-reactive-and...




Author here. Thanks for the thoughtful reply!

I did indeed mix up `useMemo` and `React.memo` – fixed it in the post.

You're right, I am skipping a lot of details (hence "to grossly oversimplify"). I know that React doesn't invalidate the whole tree, but it does in the worst case. Maybe I should add a note about that.

Svelte not being truly reactive makes perfect sense, but in Svelte v5 my understanding is that "runes mode" does exactly that. This is what I mean by "moving in that direction."


Hard to ride the line between clear, concise explanation and perfect technical correctness; I thought you picked good tradeoffs in your article.


Appreciate the response! You're right on Svelte v5; I just confirmed that Svelte's new runes are indeed reactive:

    let count = $state(0);
    
    function increment() {
      count += 1;
      console.log(count + " + 1 = " + countPlusOne);  // prints "1 + 1 = 2"
     }

    let countPlusOne = $derived(count + 1);


could you explain why this demonstrates svelte is reactive?

What's the definition of reactive is I think my question and having a clear demo is useful - if I understood it it looks a useful piece code


I never used svelte, so it’s probably a weird question, but how is increment() called?


The calling location has been omitted from the snippet. You don't need to do anything special to call it, just `increment()` wherever it's in scope.

`<button on:click={() => increment()}>+</button>`


> I know that React doesn't invalidate the whole tree, but it does in the worst case

You mean *invalidate the whole subtree, right?


> "useMemo doesn't prevent that, but React.memo can"

You can definitely use useMemo with JSX elements to prevent child components from being re-rendered too often.

There's an example right in the React Hooks FAQ where it reads: "Conveniently, useMemo also lets you skip an expensive re-render of a child"

https://legacy.reactjs.org/docs/hooks-faq.html#how-to-memoiz...

AFAIK there's no magic to React.memo. It's basically a shorthand for useMemo that takes the props as the dependency.


> AFAIK there's no magic to React.memo. It's basically a shorthand for useMemo that takes the props as the dependency.

Pedantic note: this isn't quite true. memo() also allows a second `arePropsEqual` argument that useMemo doesn't have. Also, memo() compares individual prop values, while useMemo() can only look at the whole props object (which would be "fresh" on every render -- it's a diffferent object, even if it has the same values). So it's not like you can easily reimplement memo() via useMemo(). But of course, conceptually they are pretty close :)


> “Also, memo() compares individual prop values, while useMemo() can only look at the whole props object”

Passing “Object.values(childProps)” as the dependency array for useMemo should do the same thing.

But yeah, there are good reasons to use React.memo for convenience with props. It’s not fundamentally different though, and you can definitely useMemo() for caching components when more convenient.


Using `useMemo` without using `React.memo` on the child component does not prevent a rerender at all.


> You can definitely use useMemo with JSX elements to prevent child components from being re-rendered too often

Only if those child components are memoized. By default, whenever the state of a component changes, React will rerender the entire subtree. The only time it doesn't is when a child component is memoized (React.memo) AND the props haven't changed. Utilizing useMemo and useCallback is how we prevent non-primitive props from being recreated unnecessarily


React actually has a little-known "same element reference" optimization. If your component returns the exact same JSX element reference in the same spot in consecutive renders, React will bail out of rendering that subtree, regardless of whether or not the child component is wrapped in `React.memo()`. This allows the parent component to control the behavior. So yes, `useMemo` would be how you do that:

- https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-...


I'm not sure what you're arguing here.

useMemo() works for memoizing child elements. I linked to the React docs showing this.


I see what you mean. I'm a little shocked the docs have an example of it being used in this way. Using `useMemo` in this way is generally considered a bad practice and a "hack". The new version of the react docs does not have an example of useMemo being (mis)-used in this way


The quote quite literally states “grossly oversimplify”. It being “not quite” correct is sort of the aim, for the sake of conveying a broader point.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: