Hacker News new | ask | show | jobs
by eatonphil 1701 days ago
I like React a lot and have used it professionally for more than 5 years. First off I mostly haven't needed to memoize any time I can remember in any enterprise (non-SaaS) production or personal apps. But surely CoinBase is at a bigger scale than my apps were/are.

But if it's the case that memoizing is such a good thing to do despite the effort (and I'm not debating that in this question), why is React designed in a way that requires you to opt into it and write the same boilerplate all over the place?

If hooks make this a problem maybe hooks aren't the best (or at least pinnacle) design? (And I really prefer hooks, personally.)

3 comments

What does "needed" mean in "I mostly haven't needed to memoize any time I can remember"?

Does it mean that that your manager/team lead has never asked you to? Or that your production builds always hit some performance benchmark? Or that your development builds hit that benchmark? Or that you never noticed a qualitative slowdown in your development environment? Or something else?

"Needed" is a word you gotta define when you start talking about performance, unlike discussing functional correctness.

There was never a slowness in the apps I've worked on that came down to requiring memoization in React versus other basic things like doing pagination or other ways of rendering only things that would be displayed at the time for the user.
> pagination or other ways of rendering only things that would be displayed at the time for the user

Well, yes, those are alternate ways to deal performance problems, but they are not necessarily any easier than adding a bit of memoization.

No those solutions (and problems) were completely tangent to adding memoization. My point is that I've never seen a performance issue where non-memoization was the problem.
the only time I find it to be required is when passing in callbacks to custom hooks with props that may change and you'll notice immediately because the callback will continuously run
If you're using React.useCallback to avoid triggering further hooks down the line, then you're using it wrong. Since React.useCallback is ostensibly just React.useMemo wrapped around a function, this note in the documentation is just as applicable:

  You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo — and then add it to optimize performance.
You're only using it wrong if you're trying to avoid triggering hooks as something other than a performance optimization.

For example, something like this should work correctly even without useCallback, but you would be constantly re-subscribing for no good reason.

    const callback = useCallback(...);

    useEffect(() => {
        const unsubscribe = subscribe(callback);
        return () => unsubscribe();
    }, [callback]);
I was following a pattern similar to react-table, where I'm destructuring a function off of a previous hook and passing it to another hook as a callback. This allows the 2nd hook to update state in the first, which causes it to infinite loop if the function isn't wrapped. I think this pattern is more complicated than it sounds, but really helps to remove business logic from a component
If we have a component <ProfilePage id={id} onLoad={handleOnLoad} /> and inside profile page we use an effect to load from id and call handleOnLoad with the loaded profile data, then we need to put handleOnLoad in the useEffect dependencies. So we have to pass a callback wrapped in useCallback else the effect would fire every time ProfilePage rerenders.
yeah, I was thinking about this too as someone who's not super familiar with React — why isn't memoing the default behavior?
I think that's because everyone needs to debug their React app, but not everyone needs the performance. So you optimise for the most common use case, where you make debugging easier. Memoization is a form of caching, caching is hard. Most backend web frameworks don't come with a cache by default, you add one when you need the performance. It's the same here.