[HN Gopher] We memo all the things (2020)
       ___________________________________________________________________
        
       We memo all the things (2020)
        
       Author : davecardwell
       Score  : 106 points
       Date   : 2021-10-25 13:18 UTC (9 hours ago)
        
 (HTM) web link (attardi.org)
 (TXT) w3m dump (attardi.org)
        
       | andkon wrote:
       | Dumb question, but is there an equivalent concern for Vue? Or a
       | reason why this kinda checking isn't necessary there?
        
       | vlunkr wrote:
       | > If you've ever profiled a React app - even in production mode -
       | you know there is a non-negligible performance impact to every
       | component that renders.
       | 
       | Maybe it's just me, but I've used React for ~5 years and I've
       | never needed to profile an app, since the performance out of the
       | box has always been good enough.
        
         | jbaudanza wrote:
         | The situation is much more severe with react-native, which
         | doesn't have a JIT compiler available.
        
       | kecupochren wrote:
       | I find the state of things in React, pun intended, a bit sad.
       | Hooks are definitely an improvement over class based components
       | but it still suffers from the same issue - having logic and state
       | in the view layer leads to spaghetti code. Not to mention
       | dependency arrays which are easy to get wrong and the weird
       | syntax you end up with everywhere.
       | 
       | I'm a big fan of MobX and it pains me to no end that it didn't
       | took off better. It's a godsend from like 5 years ago and it
       | makes so many of these React pain points disappear.
       | 
       | Instead of adding state to your components here and there, it
       | works outside of the view layer. You define the model, derived
       | computed views, actions and then just use it inside your
       | components. You never ever worry about performance because MobX
       | knows what is used where and it will optimize your renders
       | automatically.
       | 
       | Moreover, dealing with state outside of the view layer makes it
       | much more easier to refactor, reason about and test your app.
       | Sure, you can do the same with Redux but it's 10x more code.
       | 
       | I recommend this article on this topic by the author -
       | https://michel.codes/blogs/ui-as-an-afterthought
        
         | brundolf wrote:
         | I +1 MobX wherever I see it mentioned, but I have to disagree
         | here:
         | 
         | > having logic and state in the view layer leads to spaghetti
         | code
         | 
         | Sometimes it makes sense to put logic and state in your view
         | components, and the wonderful thing about MobX is that it
         | doesn't care. It lets you freely move your state around to
         | wherever you want it to live: inside components, outside
         | components, in a module-scoped object, in a global store, all
         | of the above. It's just JavaScript objects.
         | 
         | For those fighting with hooks: one of the best things about
         | MobX is that it does all dependency-tracking (for effects, but
         | also for components) automatically and flawlessly. An entire
         | problem-space that's usually easy to mess up just vanishes in
         | front of your eyes. Going back to anything else feels like
         | going back to the dark ages.
        
           | kecupochren wrote:
           | > Sometimes it makes sense to put logic and state in your
           | view components
           | 
           | Of course, I do that a lot with generic, reusable components.
           | Once I know it's too complex I extract it to model that gets
           | passed through props. Win/win
        
           | morgancmartin wrote:
           | I'm not familiar with MobX, but I am a big fan of Jotai
           | (https://jotai.pmnd.rs/). It is a spiritual offshoot of
           | Facebook's experimental(?) Recoil library.
           | 
           | It is a bottom up approach to state. Everything is modeled as
           | atoms. Atoms can be defined in any module and are accessed by
           | simply exporting/importing from/to the module. Simply call
           | the useAtom hook and you're now using that state atom.
           | 
           | Under the covers it is scoped via a top-level React context,
           | I believe.
           | 
           | Atom derivation, read/write, async, it's all there. It also
           | hooks into a lot of other popular state libs like redux,
           | XState, Zustand and many others.
           | 
           | I much prefer it to Redux because there is zero boilerplate
           | and extremely flexible. It can be easy to hang yourself with
           | all the extra rope it gives you if you aren't careful though.
        
         | notpachet wrote:
         | This 100%. I still don't understand why React devs are so
         | infatuated with colocating business logic with the UI that
         | presents the result of that business logic. Sure, in the small
         | (a todo list app? a weekend project?) it's probably a lot
         | easier to reason about if you just jam everything into the same
         | file. But why is it so difficult for people to see that the
         | reason their large application is bloated, untestable,
         | unmaintainable, etc is directly due to the blatant violation of
         | separation of concerns that they're parroting?
         | 
         | I feel like part of this is due to some devil's bargain on the
         | part of the React maintainers. They want mindshare, and they
         | know that it's easier to gain mindshare if the behaviour of the
         | app appears simpler, and that appearance of simpler is easier
         | to achieve if the behaviour is relegated to a smaller number of
         | files...
        
           | nfRfqX5n wrote:
           | but hooks allow you to easily move business logic outside of
           | your component. most business logic is simple so people use
           | it inline. isolating it makes it pretty easy to test and
           | reuse
        
             | notpachet wrote:
             | That's true. But to echo the underlying theme of the
             | original blog post, it is difficult to ensure that a large
             | team of developers (of varying skill levels) maintains a
             | consistent approach to this. Different developers likely
             | have different opinions of where that "simple" threshold is
             | that warrants factoring out the business logic. And, when
             | the push of a deadline comes to shove, it is tempting to
             | just throw all the shit in the component with the promise
             | that we'll refactor it at a later date.
             | 
             | More fundamentally, I feel like putting business logic
             | hooks in a component (even simple ones) sacrifices the
             | cleanliness of components as simple stream transformers:
             | input some scalar props, output some HTML. As soon as you
             | start calling hooks within a function component, it's no
             | longer purely functional. You have side effects. And those
             | side effects result in a component that's trickier to debug
             | and trickier to test.
        
       | senand wrote:
       | This should have ,,React:" mentioned in the title.
       | 
       | I was thinking about a technique to write things down...
        
       | nop_slide wrote:
       | Interesting, I mostly followed this approach which is to
       | basically never use those constructs unless you are 100% certain
       | you know what will happen.
       | 
       | https://kentcdodds.com/blog/usememo-and-usecallback
       | 
       | TLDR;
       | 
       | > Specifically the cost for useCallback and useMemo are that you
       | make the code more complex for your co-workers, you could make a
       | mistake in the dependencies array, and you're potentially making
       | performance worse by invoking the built-in hooks and preventing
       | dependencies and memoized values from being garbage collected.
       | Those are all fine costs to incur if you get the performance
       | benefits necessary, but it's best to measure first.
        
         | jakelazaroff wrote:
         | The problem with avoiding useCallback is that another hook will
         | bite you: useEffect. If you need to define functions that
         | interact with your component's state, you _have_ to memoize
         | them with useCallback (or useRef) to avoid a useEffect infinite
         | loop.
         | 
         | What's even worse is that if functions passed as _props_ are
         | unstable, your useEffect will run every time the parent
         | component renders -- meaning that a component can 't trust
         | functions passed into it.
         | 
         | This is one of many reasons I think useEffect is a huge
         | footgun, and I really wish we had a better primitive for
         | causing side effects.
        
           | antihero wrote:
           | I wouldn't say useEffect is a footgun, it just requires
           | realising that React is doing shallow comparisons.
        
             | nfRfqX5n wrote:
             | very good point
        
           | deckard1 wrote:
           | hooks in general are a huge footgun. You need to place them
           | at the preamble of your function (and not nested). They have
           | to be named with "use" prefix (worth mentioning is React
           | basically commandeered the entire "use" namespace for their
           | own purposes via lint enforcement, which will bite you in the
           | ass eventually), and they are poorly designed.
           | 
           | Take useRef for example. You'd logically expect it to work
           | with useEffect and that would be how you use refs in hooks
           | land. But of course, refs are still a design wart on React
           | (they've been through, what, 4 iterations now and they still
           | can't figure out the interface?!). So of course you need to
           | use useCallback. So what is the point of useRef then? I have
           | no idea. The only use I've found is for "instance" variables.
           | Or maybe onClick callbacks that run later. But now you have a
           | ref that only works in some cases and not others. Yay,
           | "composability"
           | 
           | Browse the React docs and you'll find the caveat-to-design
           | ratio is exceedingly high. On any other project you'd assume
           | this is beta or alpha ware.
        
             | gherkinnn wrote:
             | useRef can be used to hold a reference to DOM elements,
             | useful for breaking out of Reactland or to hold and mutate
             | values that should not cause a rerender.
        
         | antihero wrote:
         | > you could make a mistake in the dependencies array,
         | 
         | This is an auto-fix with eslint, and when it isn't exactly
         | right (you need a "one way update") you can override that rule.
         | 
         | I would posit that passing a value that is regenerated every
         | render (as opposed to when it actually changes) outside of the
         | component (via props or context) is much more dangerous and
         | likely to create infinite loops. For stuff that stays internal,
         | sure, knock yourself out (until it is required by a useEffect
         | or anything else that needs dependencies).
        
       | jasonkillian wrote:
       | This is a great article and I agree with it fully.
       | 
       | The argument that a lot of popular React voices have made, "React
       | is fast and it's prematurely optimizing to worry about memoizing
       | things until a profile shows you need it", has never rung true
       | with me. First and foremost, there's a huge time cost to figuring
       | out what those exact spots that need optimization are, and
       | there's also an educational cost with teaching less experienced
       | engineers how to correctly identify and reason about those
       | locations.
       | 
       | There are only two reasonable arguments for not using `memo`,
       | `useMemo`, and `useCallback`. The first is that it decreases devx
       | and makes the code less readable. This one is true, but it's a
       | very small cost to pay and clearly not the most important thing
       | at stake as it's only a slight net effect. The second argument is
       | that the runtime cost of using these constructs is too high. As
       | far as I can tell, nobody has ever done a profile showing that
       | the runtime cost is significant at all, and the burden of proof
       | lies with those claiming the runtime overhead is significant
       | because it doesn't appear that it is typically when profiling an
       | app.
       | 
       | So, given that the two possible reasons for avoiding `memo`,
       | `useMemo`, and `useCallback` are not convincing, and the possible
       | downsides for not using them are fairly large, I find it best to
       | recommend to engineering teams to just use them consistently
       | everywhere by default.
        
         | Zababa wrote:
         | I've always thought of "premature optimisation" as optimising
         | something that's not your "hot path". If there's no clear hot
         | path, everything is the hot path, and small optimisation gains
         | everywhere are the only thing you're going to get. So at this
         | point, it's not premature.
         | 
         | You could also rewrite your code so that there is a clear hot
         | path, but in that case it seems to be React rendering, that's
         | optimised by using memo and avoiding it completely.
        
           | wpietri wrote:
           | How could you not have a hot path? You're saying that you've
           | measured actual usage and discovered that each thing happens
           | to be called exactly the same number of times? That strikes
           | me as extraordinarily improbable.
        
             | Zababa wrote:
             | That's not exactly it. It's more of a "If you have nothing
             | that takes more than 1% of your resources, no single
             | optimisation can get you more than a 1% reduction in your
             | resources". That seem to be how most web apps are: you
             | parse a little bit of HTTP, a little bit of JSON, you
             | validate a few things, you call the database, that does a
             | few things too, you have a bit of business logic, you call
             | the database again, then have a bit of glue code here and
             | there, and finally respond to the user with a little bit of
             | HTTP and maybe some HTML, maybe some JSON.
             | 
             | If that's how your app works and nothing can be optimised
             | significantly, that's usually here where you can make big
             | gains in performance by changing a big thing. One of these
             | big things might be to put a cache in front of it, because
             | a cache hit will be way faster than responding again to the
             | same request. Another could be to change language. For
             | example, from Python to Go. Since Go is (most of the time)
             | a bit faster on everything, you end up being faster
             | everywhere. Or even from Python to PyPy, a faster
             | implementation. Another could be redesigning your program
             | so that you have one single obvious hot path, and then
             | optimising that.
             | 
             | That seem to be the case for them here: no component is
             | taking all of the resources, but by using memo everywhere,
             | all of them take less resources, which leads to a good
             | reduction of resources in general.
        
           | deckard1 wrote:
           | The death from a thousand papercuts.
           | 
           | I'm not terribly convinced with memoization though. You're
           | using extra memory, so it's not free optimization. We have
           | Redux memoized selectors everywhere. I can't help but wonder
           | how much of that is actually a memory leak (i.e. it's never
           | used more than once). Granted, components are a bit
           | different.
           | 
           | I always do cringe when I see a lint rule forcing you to use
           | a spread operator in an array reduce(). It's such a stupid
           | self-inflicted way to turn an O(N) into an O(N^2) while
           | adding GC memory pressure. All to serve some misguided dogma
           | of immutability. I feel there is a need for a corollary to
           | the "premature optimization is the root of all evil" rule.
        
             | Zababa wrote:
             | > I always do cringe when I see a lint rule forcing you to
             | use a spread operator in an array reduce(). It's such a
             | stupid self-inflicted way to turn an O(N) into an O(N^2)
             | while adding GC memory pressure. All to serve some
             | misguided dogma of immutability. I feel there is a need for
             | a corollary to the "premature optimization is the root of
             | all evil" rule.
             | 
             | I think a rule of "don't try to use X as if it was Y" would
             | be reasonable. I love immutability, but the performance
             | cost in JS is really high. Many people are fine with using
             | Typescript to enforce types at compile time and not at
             | runtime. Maybe many people would be fine with enforced
             | immutability at compile time (Elm, Rescript, OCaml, ...)
             | and not runtime?
        
         | napsterbr wrote:
         | > has never rung true with me.
         | 
         | Yeah, me neither. I'm seeing first-hand a "large" (but probably
         | not Coinbase-large) webapp dying by 10 thousand cuts.
         | 
         | The "you shouldn't care if it rerenders" components are,
         | together, affecting performance. Going back and memoizing
         | everything would be a nightmare and not a viable business
         | solution. Rewrite everything from scratch is also not viable.
         | So we have to live with a sluggish app.
         | 
         | At the same time, memoizing everything does make your code
         | unreadable.
         | 
         | Honestly, it's a mess. I only accept working with this kind of
         | stuff because I'm very well paid for it.
         | 
         | On my personal projects I stay far away from the Javascript
         | ecosystem, and it's a bless. Working with Elm or Clojurescript
         | is a world of difference.
         | 
         | Clojurescript's reframe, by the way, uses React (via Reagent)
         | and something somewhat similar to Redux, without having any of
         | the pitfalls of modern JS/React.
         | 
         | I can write a large application and ensure that there are no
         | unnecessary rerenders, without sacrificing readability and
         | mental bandwidth by having to memorize everything.
         | 
         | The conclusion I have, which is personal (YMMV) and based on my
         | own experience, is that modern JS development is fundamentally
         | flawed.
         | 
         | Apologies for the rant.
        
         | wpietri wrote:
         | It seems to me you're being pretty breezy about readability. At
         | most places, developer time is by far the most expensive
         | commodity, and the limiting factor in creating more user value.
         | 
         | In particular, bad readability is one of the sources of a
         | vicious circle where normalization of deviance [1] leads to a
         | gradual worsening of the code and a gradual increase in
         | developer willingness to write around problems rather than
         | clean the up. Over time, this death by a thousand cuts leads to
         | the need for a complete rewrite, because that's easier than
         | unsnarling things.
         | 
         | For throwaway code, I of course don't care about readability at
         | all. But for systems that we are trying to sustain over time,
         | I'm suspicious of anything that nudges us toward that vortex.
         | 
         | [1] https://en.wikipedia.org/wiki/Normalization_of_deviance
        
           | jasonkillian wrote:
           | I don't disagree with you on readability being important or
           | on the value of developer time. It's just that the marginal
           | costs of `memo`, `useMemo`, and `useCallback` are quite low.
           | They don't add cyclomatic complexity, they don't increase
           | coupling, they can be added to code essentially mechanically
           | and don't carry a large cognitive overhead to figure out how
           | to use, etc.
           | 
           | The main downsides are that they take slightly longer to type
           | and slightly decrease the succinctness of the code. And then
           | there are a few React-specific complexities they add
           | (maintaining the deps arrays and being sure not to use them
           | conditionally) but these should be checked by lint rules to
           | relieve developer cognitive load.
           | 
           | Of course I'd rather not have these downsides, but in the
           | end, it's still much less developer overhead than having to
           | constantly profile a large application to try and figure out
           | the trouble spots and correctly test and fix them post-hoc.
           | And it means users are much more likely to get an application
           | that feels snappier, doesn't drain as much battery, and just
           | provides a more pleasant experience overall, which is worth
           | it imo.
        
       | lawwantsin17 wrote:
       | I like that in the end he compared React to a virus that's
       | ruining lives and it's solution to a universal mandate. I've got
       | one for you. Don't use React with static content.
        
       | eatonphil wrote:
       | 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.)
        
         | nfRfqX5n wrote:
         | 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
        
           | jdjb wrote:
           | 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.
        
             | acsreedharreddy wrote:
             | 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.
        
             | TheCoelacanth wrote:
             | 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]);
        
             | nfRfqX5n wrote:
             | 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
        
         | marcellus23 wrote:
         | yeah, I was thinking about this too as someone who's not super
         | familiar with React -- why isn't memoing the default behavior?
        
           | Zababa wrote:
           | 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.
        
         | fouric wrote:
         | 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.
        
           | eatonphil wrote:
           | 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.
        
             | TheCoelacanth wrote:
             | > 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.
        
               | eatonphil wrote:
               | 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.
        
       | cheeew wrote:
       | I've normally heeded to the advice from Dan Abramov
       | (https://overreacted.io/before-you-memo/) and KCD
       | (https://kentcdodds.com/blog/usememo-and-usecallback): mainly due
       | to the fact that I figured performance would take a significant
       | hit by using unnecessary React.memo / useMemo calls throughout
       | the codebase.
       | 
       | One negative side-effect I could see as a result of this pattern
       | is devs becoming too reliant on these optimizations and
       | neglecting composition.
       | 
       | But I suppose if the performance gain is substantial enough and
       | DX isn't negatively impacted too much, it could serve as
       | worthwhile-- especially at the level of scale which Coinbase
       | requires.
        
       | steve_adams_86 wrote:
       | I don't disagree that this likely improves performance in most
       | cases, and I don't blame the author here for any of my concerns.
       | 
       | We've implemented this in our code base and it's awful. Yes it
       | improves performance. It also makes debugging terrible. Combined
       | with contexts, the react dev tools are virtually useless anywhere
       | below a context with a memoized value.
       | 
       | Profiling is harder because of frameworky misdirections as well.
       | You can do coarse benchmarks but actually following code in a
       | profile gets noticeably worse once you memo everything.
       | 
       | I hope this is fixed. I really enjoy react, but this odd thing
       | about it - that we arguably should memoize everything manually,
       | and that it does make the dev tools a mess, is a huge hit to
       | developer experience.
       | 
       | So tired of "Component did not render" in the Component tab.
        
       | jon-wood wrote:
       | This feels to me like another example of how the drive to use
       | nothing but functional components in React is harming
       | readability. Class based components were allowed to define a
       | `shouldComponentUpdate` method which would be called ahead of
       | rendering to decide whether a re-render is needed.
       | 
       | Having the parent component memoise the component instead feels
       | like a step backwards as we're now asking the parent to carry an
       | understanding of a child component's implementation to decide
       | whether re-renders are needed, rather than allowing the child to
       | communicate that up the tree.
        
         | beaconstudios wrote:
         | the parent doesn't have to memoise the component though. You
         | can do this:                   export default
         | React.memo(function myComponent(props) {           //
         | implementation         });
         | 
         | though you would likely want to set displayName before
         | exporting, in reality.
        
           | FalconSensei wrote:
           | But that is still memo-ing, just in a different part of the
           | code. And I'm not sure wrapping all components in React.memo
           | is a good practice, otherwise all components would be memo-ed
           | by default. `shouldComponentUpdate` is more explicit
        
           | jon-wood wrote:
           | In which case, I stand corrected. I've not used React for a
           | while and wasn't aware that was possible.
        
         | ramesh31 wrote:
         | Have you ever dug through a complex heavily nested application
         | trying to debug a performance issue, only to find a custom
         | shouldComponentUpdate method within every individual component?
         | It makes debugging an absolute nightmare.
        
           | brundolf wrote:
           | I'm not sure why it would. The profiler will tell you exactly
           | which component is the bottleneck, and you could then go
           | inspect that one for the cause.
        
             | ramesh31 wrote:
             | >The profiler will tell you exactly which component is the
             | bottleneck, and you could then go inspect that one for the
             | cause.
             | 
             | And then you have to understand the entire thought process
             | and business logic that led to how the
             | shouldComponentUpdate method for that class is implemented
             | for every bottleneck, where one mistake or oversight can
             | lead to an infinite re-render loop. This is the kind of
             | stuff that should be handled at the framework level or with
             | your state management library, not individual components.
        
           | psadri wrote:
           | What is your proposed alternative?
        
             | notpachet wrote:
             | Not the OP, but in a word: Redux.
        
               | nsonha wrote:
               | no?
               | 
               | If you want state management you use a state management
               | library. If you want optimization, you do memo, or pure
               | component. You don't rely on the fact that some state
               | library does that for you. You don't want your
               | component's performance changes drastically when you
               | refactor to context or whatever
        
               | kecupochren wrote:
               | What? Redux doesn't do any performance optimizations.
        
               | notpachet wrote:
               | Not by itself, but most people who use React + Redux use
               | the (unsurprisingly named) react-redux glue library, too.
               | That does a lot of the "should component update"
               | calculations for you as a function of the computed
               | `map[State/Dispatch]ToProps` result. (There are still
               | some gotchas with caching selectors and so on, but I
               | personally find those a lot easier to implement post-fact
               | than memoizing hook soup codebases once you realize you
               | have a problem.)
        
               | kecupochren wrote:
               | Oh, I never knew that. TIL
        
             | ramesh31 wrote:
             | >What is your proposed alternative?
             | 
             | Precisely what the post describes. Functional components
             | and memoize all the things.
        
       | nathias wrote:
       | This is an antipattern for a reason. Not only is the code less
       | readable, it builds bad habits of code splitting state management
       | and overall structure. A much better alternative is to just learn
       | to understand the tools you are using better.
        
       | jbaudanza wrote:
       | From the useMemo docs: https://reactjs.org/docs/hooks-
       | reference.html#usememo
       | 
       |  _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._
       | 
       | I think about this section a lot. If they actually changed
       | useMemo to sometimes "forget" values, it would break so many
       | useEffect dependency arrays (including my own).
        
       | d23 wrote:
       | I have basically no interest in frontend stuff, but I can't stop
       | staring at this page. I think it's the overall color scheme and
       | that body font. It's gorgeous.
        
       | ald890 wrote:
       | I created the benchmark for this.
       | 
       | Because in every aspect it seems that React.memo is better.
       | Especially when we are sure of stable argument references.
       | 
       | Even when you add children to the component with memo, the worst
       | case performance will be the same.
       | 
       | https://codesandbox.io/s/react-memo-benchmark-m2bk6?file=/sr...
        
       | Arch-TK wrote:
       | This was in 2020. I assume the team got made redundant in the
       | last year or something. Coinbase has genuinely been the slowest
       | performing website I've used in the past couple of years.
        
         | fabiendem wrote:
         | I asked the author on Twitter if this approach was still in
         | place, but didn't get a reply :/
        
         | steadicat wrote:
         | The team actually became part of a company-wide effort called
         | Client Foundations! And no, we haven't changed our mind on
         | this. (BTW we're hiring. :))
        
       | have_faith wrote:
       | It certainly feels like a failing of the hooks design that these
       | subjects are so common (I love hooks generally!). When someone
       | introduces a new paradigm that by design has a list of footguns
       | to avoid you can't help but wonder if this was necessary.
       | 
       | Has anyone tried tackling a hooks-like api that fixes the known
       | pitfalls? encapsulating shared logic with hooks is a massive
       | benefit but the subtleties can be difficult to teach to others.
        
       | meowtimemania wrote:
       | Has anyone added a compilation step that adds all the memoization
       | boilerplate for you?
        
         | hyzyla wrote:
         | I think it can be a solution to readability problem
        
       | Zababa wrote:
       | There's no mention of what I think is the most important point:
       | how is this enforced? If that's with a tool, I think it's great
       | and a sane way to do things. If it's by asking everyone to
       | remember doing it, I think it's a missed opportunity.
       | 
       | It's also interesting to see the age-old functional programming
       | problem: you trade performance for ease of development. I think
       | these days people assume that things like immutable data
       | structures are optimised under the hood. That doesn't seem to be
       | the case with React, as you have to explicitly use a performance
       | trick everywhere.
       | 
       | Their argument that it would be premature optimisation to think
       | about where memo is not needed makes sense, it's an interesting
       | shift of optimisation of the runtime performance vs optimisation
       | of the dev time.
       | 
       | > Using memo and its cousins everywhere is a sane default. It's
       | like a mask mandate during a coronavirus pandemic. Sure, we could
       | have everybody tested every day and only ask people who are
       | actively contagious to wear a mask. But it's far cheaper,
       | simpler, and ultimately more effective to ask everybody to wear a
       | mask by default.
       | 
       | That's a good metaphor. It's easier for the people who decide, by
       | shifting the burden on everyone else. I personally get headaches
       | by wearing a mask all the time at work. I think I may get
       | headaches too if I had to remember something like this all the
       | time.
        
         | nfRfqX5n wrote:
         | I think it would be easy to create a rule to see if the default
         | export is wrapped in memo, but you could also just have it as a
         | coding standard
        
           | BinaryBullet wrote:
           | I wonder if this is the plugin they are using:
           | 
           | https://github.com/steadicat/eslint-plugin-react-memo
           | 
           | Does anyone know of any other eslint plugins that help
           | enforce this?
        
             | fabiendem wrote:
             | The author of the article wrote the ESLint plugin:
             | https://github.com/steadicat So they probably use(d) it.
        
               | Zababa wrote:
               | That's great!
        
           | Zababa wrote:
           | What do you mean by coding standard? My point was that if
           | it's enforced by tool, either as a reminder, or an automatic
           | modification, it's fine, but if it's not, it's annoying.
        
       | jamespwilliams wrote:
       | Kind of makes you wonder why React.memo isn't just the default
       | behaviour.
       | 
       | https://github.com/facebook/react/issues/14463#issuecomment-...
       | suggests it was meant to be the default behaviour, but was
       | scrapped because it would "break backwards compatibility". No
       | source is given for that claim though.
        
         | baxuz wrote:
         | https://overreacted.io/before-you-memo/
         | 
         | https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-...
        
       ___________________________________________________________________
       (page generated 2021-10-25 23:02 UTC)