[HN Gopher] Why React Re-Renders
       ___________________________________________________________________
        
       Why React Re-Renders
        
       Author : clessg
       Score  : 136 points
       Date   : 2022-08-16 16:50 UTC (6 hours ago)
        
 (HTM) web link (www.joshwcomeau.com)
 (TXT) w3m dump (www.joshwcomeau.com)
        
       | synu wrote:
       | If you don't mind a slight tangent, where would you start today
       | to learn front end development with React such that you learn
       | this sort of thing as you go?
        
         | jasim wrote:
         | This is diffused cultural knowledge, but most of the ideas in
         | React can be understood as: view = render(state). It re-renders
         | everything all the time. But practical considerations force
         | some optimizations. Everything else in React follows from those
         | optimizations.
         | 
         | For example, if you destroy and re-create DOM all the time,
         | then it loses critical information like user's cursor position
         | and text selections. It is also slow to read and write to the
         | DOM. Thus the need for an intermediate data structure, the
         | virtual DOM.
         | 
         | React re-renders the virtual DOM every time the state changes.
         | And it then diffs the previous and current ones against each
         | other and does just the minimal number of DOM mutations to sync
         | it up. To speed this up a bit, array elements are denoted with
         | "key" so (I assume) there is a way to see if an element has
         | been added or deleted.
         | 
         | But re-rendering the virtual DOM all the time can also be
         | costly in terms of performance. Thus the next set of
         | optimizations: React.memo+immutable data, and so on..
        
         | lhnz wrote:
         | The new version of the official docs is currently in Beta and
         | this is really, really good: https://beta.reactjs.org/learn
         | 
         | (In fact, I'll go further than this and add that the section on
         | "Escape Hatches" should be re-read by senior/lead engineers, as
         | many have misconceptions due to learning concepts ad-hoc from
         | code of mixed quality: https://beta.reactjs.org/learn/escape-
         | hatches)
        
         | gregsadetsky wrote:
         | Scrimba has pretty great interactive classes too. They
         | specifically have a free React one:
         | https://scrimba.com/allcourses?topic=react
         | 
         | It's quite high quality and the learning environment is great:
         | you're in a live code editor + hear and see the teacher's
         | code/cursor movements.
        
         | azangru wrote:
         | If you are starting to learn front-end development today, you
         | may question the choice of React.
         | 
         | Consider that a decade ago, people who were starting with the
         | frontend were learning jQuery, which is almost irrelevant now.
        
           | ramesh31 wrote:
           | >Consider that a decade ago, people who were starting with
           | the frontend were learning jQuery, which is almost irrelevant
           | now.
           | 
           | It's not that simple. At the time, jQuery was absolutely
           | pivotal in bringing about ES5 and the transpilation
           | revolution on the front end. More or less its' entire API was
           | subsumed by the browsers, and so jQuery became _unnecessary_
           | , but far from irrelevant.
           | 
           | I can see the same thing happening today with React/JSX.
           | There is simply no better way of expressing a UI than JSX-
           | like components. And FRP as a paradigm for UI development is
           | here to stay. So the future of web dev probably looks
           | something like Yew [0].
           | 
           | [0] https://yew.rs/docs/getting-started/build-a-sample-app
        
           | outworlder wrote:
           | What would they be using instead?
        
             | azangru wrote:
             | They should probably start with native browser apis for DOM
             | manipulation, and web components. And then explore the
             | current landscape for options that alleviate the pain
             | points discovered while learning (e.g. Lit is nice for
             | declarative reactive components). All the while being
             | conscious of the tradeoffs.
        
               | gherkinnn wrote:
               | It does help to have used the basics to understand the
               | benefits of a full framework. But learning things bottom-
               | up isn't suitable for everybody.
               | 
               | As for web components, I'd rather not. Nothing about it
               | works for me. Not the class-based decorator syntax. Not
               | the CSS scoping. Not the use of custom elements. The prop
               | syntax is awful and the paradigm just feels cumbersome.
               | 
               | I work with Angular (its component model is close enough)
               | and have read the Lit docs. Never will I choose that
               | option.
               | 
               | A function is just a better way to write UIs.
        
               | 411111111111111 wrote:
               | That's a fine idea if you're not expecting the team to
               | grow beyond the original author(s).
               | 
               | It's a pretty terrible idea if you're going to do it in a
               | business setting, as the original author(s) will always
               | be it's Achilles tendon, making the project a liability
               | before it even goes into production.
               | 
               | Most projects use react or angular because it makes
               | onboarding new members easier, and these frameworks
               | really aren't as bad as some people on hn claim.
        
               | azangru wrote:
               | How much have you researched this space? Do you know of
               | companies that are successfully building their products
               | with web components? Hint: these would include Adobe,
               | Microsoft, RedHat, and GitHub. How do they onboard new
               | members to their terrible setup, one might wonder?
        
               | RussianCow wrote:
               | > How do they onboard new members to their terrible
               | setup, one might wonder?
               | 
               | I can't speak for the specific companies you listed, but
               | the number of times I've heard someone sing praises about
               | a homegrown UI framework at their place of employment is
               | approximately zero. The sentiment expressed about those
               | is generally hatred and agony.
               | 
               | That's not to say it _can 't_ be done well, but most
               | don't. Also, a company being able to hire/onboard
               | engineers does not imply that their onboarding process is
               | smooth, or that their house-made framework is well
               | designed.
        
               | azangru wrote:
               | > a homegrown UI framework
               | 
               | I am deeply puzzled by both your and the sibling comment,
               | which suggest that the only way to go is to build a
               | framework. To advance such argument, especially when
               | comparing something to React, is to forget that:
               | - React also for a long time was advertised as a view-
               | layer library for creating UI components, not as a
               | "framework".         - There've been numerous debates in
               | which advocates of Angular or Ember were suggesting that
               | because of such inherent lack of structure, React apps
               | were always different between projects, as opposed to the
               | clear conventions used in Angular or Ember project. This
               | did not deter React supporters and did not prevent React
               | from succeeding.         - React was created as a library
               | when web browsers did not have a standardized component
               | model; just as jQuery was created as a library when
               | browsers did not have a unified way of interacting with
               | the DOM. Years have passed, and web browsers have matured
               | to the point when a native component model has become a
               | reality. You do not need to home-grow a framework in
               | order to take advantage of them.
        
               | ReadTheLicense wrote:
               | Problem is, Web Components still don't support reactivity
               | and passing complex props, so you need a framework
               | anyways, and at that point it might as well be React.
               | 
               | I've seen people do abominations like each web component
               | is a React root, message passing systems on the side for
               | complex objects... better use React directly
        
               | nwienert wrote:
               | Was going to say the same as sibling @ReadTheLicense, but
               | further Web Components were started _before_ React so the
               | idea that they are more modern isn 't true.
        
               | 411111111111111 wrote:
               | Sure, if that's the scale of your project right from the
               | start then creating a new framework from scratch is
               | always an option.
               | 
               | That's the origin of both react(Facebook) and
               | angular(google) after all.
        
               | cercatrova wrote:
               | The phrase is Achilles' heel for which the tendon is
               | named.
        
           | nfRfqX5n wrote:
           | If you want a job, learn react
        
         | ng12 wrote:
         | The idea is you shouldn't really need to. You have tools to
         | memoize expensive operations in a React-friendly way, but even
         | then you shouldn't really have to think about render cycles.
         | 
         | YMMV but I the only time I've ever had to really think about
         | this stuff was when trying to frankenstein legacy jQuery code
         | into a React app.
        
           | RussianCow wrote:
           | In my experience, it's pretty easy to hit performance
           | bottlenecks in React, so I don't think it's that uncommon to
           | have to dive deeper for any reasonably complex codebase.
           | Also, you basically _have_ to understand the React render
           | cycle to effectively use `useEffect` for anything more
           | complex than  "do this thing on mount".
        
         | RyanHamilton wrote:
         | I can recommend React with Mosh:
         | https://codewithmosh.com/p/mastering-react I completed it and
         | together with the react official documentation (particularly on
         | hooks and newer react 18 features) have learnt enough to build
         | a good interactive application. Building the app immediately
         | after has taught me much more. You can try patching free
         | tutorials together but given the salary paid to good
         | developers, paying for good training is a great investment.
         | 
         | I chose react as I had a large application to make and I knew
         | react had 2 critical libraries I wanted to reuse. Having now
         | learnt react and the underlying ideas, I think Svelte
         | (https://svelte.dev/) may solve the general problem better.
         | However it has less libraries/documentation and community
         | support. If I had more time to learn I would have considered
         | learning it as a potentially superior solution.
        
         | Tiktaalik wrote:
         | I've found myself needing to learn React on the go while
         | working on an evolving React codebase, and needing to improve
         | performance significantly and it's been _very hard_ because
         | casually googling for how to do things in React yields lousy
         | hits full of extremely high level  "babys first react todo
         | app/blog" type articles.
         | 
         | Absolutely not what I need.
         | 
         | What I want to know is how to build things with React as
         | performant as possible. This discussion of complex and
         | performant apps seems elusive.
        
         | [deleted]
        
         | [deleted]
        
       | kareemsabri wrote:
       | Good article.
       | 
       | What I've found interesting is how many developers think a React
       | "component" (which since hooks is just a function) has some
       | special privileges or abilities that a normal JS function does
       | not. Like, whether it will be selectively executed or what
       | variables are created anew versus reused between subsequent
       | calls. It seems unclear that a React component is just a
       | function, and displays all the behavior expected in a plain old
       | function.
       | 
       | While I agree it was hard to know when React would re-render in
       | the old, class component paradigm, it seems much easier to know
       | when a function will re-render, since it has to re-render
       | whenever the function is called.
        
         | jasonkillian wrote:
         | It is a bit more complicated in practice though than "a React
         | component is just a function that rerenders when called". In
         | some ways, the function acts more like a class, and then React,
         | internally, uses it to create "instances" of components that
         | have their own set of data stored. (Which is why hooks like
         | useState, useRef, etc. can work - because data is being stored
         | internally in React tied to a component instance.)
         | 
         | It _is_ true that when you call a React function component it
         | "runs its code" just like any regular old JS function. But when
         | that function gets run and what all the side effects of its
         | code are actually is quite complex.
        
           | kareemsabri wrote:
           | Yeah, this is not to belittle the complexity of React under
           | the hood. But they are functions, and it seems you can assume
           | they will be called in a straightforward manner when they
           | render (whether they are invoked as explicit function calls
           | or via returned JSX).
           | 
           | The only real complexity (for the developer) is the use of
           | hooks, effects etc. if you don't mess with useMemo (which you
           | generally shouldn't). Certainly they aren't _pure_ functions,
           | they have side effects and are stateful, and that has some
           | nuances, but (kudos to the React team) once you understand
           | hooks as a reference to the instance value and a setter for
           | that value, they 're pretty easy to understand.
           | 
           | I guess I don't personally find thinking of them as a class
           | as that useful, my mental model of "it's just a function with
           | some external references (via hooks)" gets me there.
        
             | leeoniya wrote:
             | > if you don't mess with useMemo (which you generally
             | shouldn't)
             | 
             | why? is this not the primary way to re-init expensive
             | internal component state when specific props change?
        
               | hither_shores wrote:
               | GP's claim is a little too strong, but in my experience
               | most uses of `useMemo` / `useCallback` are only necessary
               | because people define things in the wrong scope, or write
               | giant spaghetti components with 15 different props and no
               | internal structure. The best memoization technique is not
               | calling things repeatedly in the first place.
        
               | kareemsabri wrote:
               | He touches on this in the piece briefly.
               | 
               | > I think as developers, we tend to overestimate how
               | expensive re-renders are. In the case of our Decoration
               | component, re-renders are lightning quick.
               | 
               | Certainly it's there for a reason, and you may have
               | expensive operations, but in my experience developers
               | reach for useMemo much too early and often, and it just
               | adds complexity to their functions. The cost of checking
               | the parameters for changes adds overhead that may be more
               | expensive than just re-doing the "expensive" operation.
               | My rule of thumb is if the operation is less than O(n)
               | where n < ~5000 I don't reach for useMemo.
               | 
               | There have been some benchmarks done on this, and when it
               | pays off to use.
        
       | petilon wrote:
       | A pain point with React is large data structures. To re-render
       | (assuming class components), you can setState with the changed
       | property. For example if your state has two properties named foo
       | and bar, and bar has changed then you call setState({ bar:
       | newValue }). This works if you have simple properties. What if
       | you have large complex data structures, and you need to modify a
       | property deep down inside? Then you can make a copy of the data
       | structure, then modify the field in the copy, then call
       | setState({ bar: copyOfLargeObject }). But it is tremendously
       | wasteful to make a complete copy of a large data structure!
       | 
       | A workaround is to not make copies of large data structures. Just
       | modify the large object directly. Then just call setState({});
       | That's right... setState() with an empty object triggers a re-
       | render. Now you don't even have to store the object being
       | modified in state. You can hold the large object in a member
       | field of the class. So even though your component is stateful,
       | you are not telling React what your state fields are - you are
       | managing it yourself. At this point, React's programming model
       | has broken down.
        
         | acemarke wrote:
         | FWIW, React has always been designed around some Functional
         | Programming type principles, such as immutable updates.
         | 
         | Immutable updates do in fact require that if you want to update
         | `state.some.nested.field`, you have to make copies of _all_
         | objects in that path: `nested`, `some`, and `state`. This isn't
         | unique to React.
         | 
         | Yes, class component `this.setState()` lets you get away with
         | mutations. That's not really a _good_ thing. If anything, it's
         | a holdover from an earlier era of JS, where it was much more
         | common to use React with data structures that might be mutable.
         | 
         | With the `useReducer/useState` hooks, the React team explicitly
         | designed them to require immutable updates and pass in new
         | references, otherwise they'll bail out, assuming that since
         | it's the same reference nothing was changed and no render is
         | needed.
         | 
         | Some more details:
         | 
         | - https://blog.isquaredsoftware.com/2020/05/blogged-
         | answers-a-...
         | 
         | - https://beta.reactjs.org/learn/updating-objects-in-state
        
           | AgentME wrote:
           | When updating deeply-nested immutable objects, the Immer
           | library is great. You call the `produce(immutableValue, draft
           | => { ... })` function with some immutable value and a
           | callback function that manipulates a mutable proxy object
           | mimicking the immutable value, and then the function returns
           | a new immutable value with the same changes made by the
           | callback function. The mutable proxy object never escapes the
           | callback, so the use of Immer stays self-contained as an
           | implementation detail of your code without infecting your
           | component's public API or anything.
           | 
           | Another alternative is the "immutability-helper" library,
           | which was originally published by the React team as "react-
           | addons-update". It's a lighter library with less proxy magic
           | going on, but at the cost of being more explicit: instead you
           | create an object describing how to update an immutable value
           | to produce a new immutable value. I've used it in the past in
           | a few places but mostly recommend Immer over it now.
        
         | hither_shores wrote:
         | > But it is tremendously wasteful to make a complete copy of a
         | large data structure!
         | 
         | You don't make a complete copy: you make a shallow copy of the
         | spine, and then only descend along the fields you actually
         | modify. The number of operations scales as O(branching factor *
         | depth), not O(size).
        
       | srk_hn wrote:
       | Can someone tell me why this page needs 13MB of resources to
       | display?
        
         | MH15 wrote:
         | My guess is for the code editors and associated transpiler. The
         | demos allow you to edit the code in JSX, requiring the tooling.
         | Kinda impressive imo.
        
         | neon_electro wrote:
         | Here are the top requests by file size from the page,
         | screenshotted since I couldn't easily copy/paste:
         | https://imgur.com/N1ANEIb
         | 
         | Would love to better understand why the site is pulling in the
         | Babel transpiler _in production_?
         | 
         | Edit: siblings know more than me, thank you siblings!
        
         | rajangdavis wrote:
         | When I checked it was 46MB! Looking at the network tab, it
         | seems to be making a bunch of extra requests for the same
         | assets.
         | 
         | I know that Vercel/Next.js will lazily load in certain JS
         | chunks but there seems to be some mechanism that is loading a
         | ton of stuff up front. Edit: from other comments in this
         | thread, it's the sandbox code, really crazy how much overhead
         | that adds to the page!
        
         | AtlasBarfed wrote:
         | Now that is how you start a flame war in the most subtle way
         | possible.
        
         | fabian2k wrote:
         | It's even more for me, it looks to me like the embedded React
         | sandboxes are essentially full React apps in development mode.
         | So none of the usual optimizations for size are active, and you
         | get the full devel-mode bundle for several React applications
         | on this page.
        
       | PeterWhittaker wrote:
       | I sometimes wonder what people are using React for, that they
       | wouldn't know this or have figured it out along the way. Let me
       | kind of explain, as best I can, without code.
       | 
       | We have a complex software product, an integrated compliance and
       | risk management system with embedded workflow, automatic
       | highlighting of potential risks due to non-compliance, plans of
       | actions (aka risk management plans), RBAC, ABAC (used to control
       | different things), etc.
       | 
       | The backend does most of the work. What gets presented at the
       | frontend can be complex.
       | 
       | The React component model gives us an almost functional DSL that
       | we use for compact, highly expressive tooling that allows us to
       | integrate common look and feel, table exports, etc., across some
       | really complex data.
       | 
       | We started before Hooks were widely available or widely known,
       | and, we started with class-based components, because we realized
       | pretty quickly we were going to have to do some funky state
       | management, especially where workflow was involved (we want a
       | common look and feel across processes and tasks, so workflow
       | tasks and processes get wrapped in higher level components that
       | call back to other high level components; the forms can have
       | dozens or hundreds of variables, some interdependent, so state
       | has to be communicated up for validation; React handles sending
       | it down).
       | 
       | Our key state management function is a custom signal handler that
       | gets passed as a prop to all sub components, then, via a common
       | wrapper, back up to the high level components that group
       | everything for display and consistency purposes.
       | 
       | As we refined this handler (and a few others), we moved from
       | class-based to functional components.
       | 
       | The functional components are simpler than the class-based
       | components they replaced, with much of the complexity located in
       | one place, the handler.
       | 
       | Our handler allows us to pass state up "just far enough", and
       | React handles updating all affected components.
       | 
       | Performance is fantastic, validation is easy(ish; it takes some
       | staring to grok how it hangs together), and debugging (once one
       | has grokked, is straightforward(ish; there are edge cases that
       | cause pause, until the "oh, yeah, that" moment).
       | 
       | That functional DSL has allowed us to build several suited-for-
       | purpose DSLs, e.g., our workflow system, which, while not no
       | code, is low code (configuration as code more than anything
       | else).
       | 
       | If we didn't understand the React state management model, none of
       | this would have been possible.
       | 
       | So I ask, in naivete, what are people building that they didn't
       | need to know that?
       | 
       | (We are likely to move to Hooks anytime soon, because we've
       | already solved the problem they were introduced for, and without
       | having to rewrite much. Hooks look like we would have to make
       | wholesale changes, in which we see little value, at least right
       | now, OMMV in the future).
        
         | gervwyk wrote:
         | Sound pretty interesting! We've also implemented a DSL on top
         | of React, see Lowdefy [0]
         | 
         | We've taken a different approach, we've written a pure js
         | engine which computes and manages state based on operator used
         | to express logic, and then have a recursive render loop in
         | react which provives engine with update hooks to it uses to
         | rerender components when it should. That way we can very handle
         | complex state logic and then update with ease all without
         | dealing with passing state up and down.
         | 
         | We still have a few ideas on how to further optimize which will
         | be built in future versions. But already we, and the OS
         | community are building some advanced apps using Lowdefy
         | 
         | [0] - https://github.com/lowdefy/lowdefy
        
         | willio58 wrote:
         | You can get away with a lack of understanding about these
         | things and still create beautiful products. For an example just
         | look at Josh's website. Beautiful react and design execution
         | without knowing these details about rerendering.
        
         | tshaddox wrote:
         | > I sometimes wonder what people are using React for, that they
         | wouldn't know this or have figured it out along the way.
         | 
         | The article is for beginners (the article itself says its
         | intended audience beginner-intermediate, but I'd say it leans
         | very much towards beginner). Thus this is precisely an example
         | of how people who use React would learn this. It would be odd
         | to comment on every explanation of a concept that everyone
         | would have already learned that concept.
        
       | fabian2k wrote:
       | The big part that seems to thoroughly confuses developers new to
       | React is the difference between rendering and reconciliation.
       | This is not particularly difficult to understand, but the
       | original emphasis on the virtual DOM seems to lead to a
       | misunderstanding on how React works. The vDOM plays a role only
       | after rendering happened, so all that diffing stuff doesn't have
       | anything to do with rendering. To me that seems like one of the
       | primary causes of developers being surprised that React rerenders
       | more than they expect.
       | 
       | I like the explanation on what triggers rendering in this post.
       | Props and state are usually used in the explanation for this
       | part, but props actually only matter if you want to use
       | React.Memo. And the one part every React developer should know is
       | that in the absence of React.Memo all children will rerender if
       | any state changes.
        
       | Bolkan wrote:
       | JS works in mysterious ways.
        
         | codingdave wrote:
         | I think that is the point, is that it does not. It is code, and
         | it does what it is told. But it is quite possible to be a
         | professional dev without fully understanding exactly how and
         | why your frameworks doing their thing, so it feels hand-wavy
         | and mysterious.
        
           | 4pkjai wrote:
           | I'm among the React developers who don't really know how it
           | works under the hood. Recently I needed to code a UI that
           | required mouse drag events. It ran like a pig when I did it
           | in React.
           | 
           | I tried a few things to speed it up, but eventually gave up
           | and did the UI in plain old Javascript. It runs a hell of a
           | lot better, but the code does feel a lot more flimsy.
           | 
           | Edit: Here's a demo of the UI I built
           | https://www.youtube.com/watch?v=Wt71bNYe3qc
        
             | isbvhodnvemrwvn wrote:
             | It's not unlikely that you missed some hints of the latter
             | part of the article (JS equality for functions or objects)
             | although it's difficult to say without seeing the code.
        
             | IceDane wrote:
             | There is nothing about react that requires you to
             | understand "how it works under the hood" to use mouse
             | events in react. You just need to sit down and read the
             | tutorials and learn to use react properly. Try the new beta
             | docs.
        
               | 4pkjai wrote:
               | True, but I'm quite happy using VanillaJS. I'd like to
               | avoid React as much as possible in the future.
        
             | cantSpellSober wrote:
             | Draggable UI (w/o libraries) is one of the places I enjoy
             | React most, maybe re-rendering wasn't to blame. Might have
             | been an issue under the hood (as drag fires multiple times
             | a second)? From the article:
             | 
             | > I think as developers, we tend to overestimate how
             | expensive re-renders are. In the case of our [pure]
             | component, re-renders are lightning quick.
             | 
             | > If a component has a bunch of props and not a lot of
             | descendants, it can actually be _slower_ to check if any of
             | the props have changed compared to re-rendering the
             | component.
        
             | spoils19 wrote:
             | I'm no expert, but mouse drag events in React are fairly
             | simple to get working performantly, even without
             | understanding how it works under the hood. There are even
             | many libraries that provide functionality, all without it
             | running 'like a pig'.
        
               | lioeters wrote:
               | Also:
               | 
               | > Can pigs run fast? Domestic pigs can run as fast as 17
               | km/h while wild pigs can reach a speed of 30 km/h!
        
               | 4pkjai wrote:
               | Yes, but I didn't want to use a library because I was
               | doing something a bit out of the usual case.
               | 
               | I do like understanding my code as much as possible. So I
               | was choosing between: 1. Understand React better, and
               | reading about the "React" way to use these mouse events.
               | 2. Doing it in VanillaJS
        
               | spoils19 wrote:
               | My point was not to use a library, but that many others
               | have implemented functionality in libraries without
               | performance decreases. Granted, your use case may be
               | special to the point where vanilla JS is better, but
               | given how many libraries are out there, as well as how
               | many may simply be poorly implemented yet still work
               | fast, makes me wonder what you were indeed doing.
        
               | ramesh31 wrote:
               | >I do like understanding my code as much as possible. So
               | I was choosing between: 1. Understand React better, and
               | reading about the "React" way to use these mouse events.
               | 2. Doing it in VanillaJS
               | 
               | The great thing about the "React" way of doing things is
               | that it's just the JavaScript way of doing things.
               | 
               | React can be summed up entirely as: "a function that
               | takes in props and returns rendered HTML". It is _not_ a
               | framework. There is no black magic. There are no idioms.
               | There are no batteries included.
               | 
               | Anything else you do with it beyond that is entirely up
               | to you.
        
               | recursive wrote:
               | "Rules of hooks" is a thing.
        
               | westoncb wrote:
               | That's a bit too strong imo. There is magic, and it can
               | generally be found in implicit re-render conditions.
        
         | IceDane wrote:
         | You seem to be conflating javascript and react here, and even
         | if you weren't, the entire point of this article is that
         | nothing works in mysterious ways.
        
       | gregsadetsky wrote:
       | Josh's content is always very very high quality. I look forward
       | to him releasing his online React course [0] so that I can
       | recommend it to others who are starting out.
       | 
       | My personal biggest not-total-comprehension is around Hooks /
       | effects. I've followed tutorials, used them in production, etc.
       | I'm comfortable using them but I also consider them a bit of a
       | black box, which I don't like (e.g. I'm not sure how they're
       | implemented). The other (even bigger) question for me is "why" --
       | what prompted the React team to change everything over to
       | "effects". Anyone?
       | 
       | [0] https://www.joyofreact.com/
        
         | HeyImAlex wrote:
         | Hooks compose, whereas side effects and memoized values
         | sprinkled through component constructors and lifecycle methods
         | do not.
         | 
         | For example, the equivalent of useEffect required calls inside
         | of componentWillMount, componentDidUpdate, and
         | componentWillUnmount. You try and make something like this re-
         | usable and you'll be leaking details of your implementation
         | across the whole component via inclusion in these lifecycle
         | methods, not to mention any data you're shoving onto the
         | component instance. But it's still doable.
         | 
         | Now, what if you wanted to use this re-usable behavior inside
         | of another re-usable behavior? It gets complicated fast! Now
         | your library needs to expose the lifecycle-updating methods of
         | the underlying library, leaking details all the way down. Hooks
         | are opaque from the perspective of lifecycle, while still
         | having access to all the same... hooks.
        
         | vanjajaja1 wrote:
         | Dan had a good summary of why hooks happened which I can't find
         | now, the tldr was that there was a bunch of bugs introduced
         | around referenced props/state being stale and unpredictable in
         | components. Hooks was the natural evolution that removed all
         | possibility of accidentally referencing stale data.
        
           | joshribakoff wrote:
           | > Hooks was the natural evolution that removed all
           | possibility of accidentally referencing stale data.
           | 
           | It unfortunately does not, you can hve various foot guns with
           | refs or omitting dependencies from the array argument; but to
           | your point it makes it a lot easier to ensure you do it
           | correctly by collocating logic related to each cross cutting
           | concern instead of entangling the code in the lifecycle
           | methods.
           | 
           | More precisely it makes it easier to follow correct patterns,
           | but as always that is subjective and hooks can be contentious
           | :)
        
         | fabian2k wrote:
         | You can reuse hooks between multiple components. You can't
         | really do that with the lifecycle methods of class-based
         | components.
        
         | knodi123 wrote:
         | Hooks feel like a good system that stopped right before it
         | became pretty. Like, an componentDidMount event is a now
         | useEffect with no second argument? But a componentWillUnmount
         | event is now a useEffect, with no second argument, that returns
         | a callback?
         | 
         | It's powerful, and it's not that hard to use, but it's cryptic
         | and random.
         | 
         | Why call it useEffect instead of some other more meaningful
         | phrase? I mean, "componentDidMount" tells you _exactly_ what it
         | is. Does  "useEffect"?
         | 
         | Why should onload things be a function, but onunload should be
         | a function returned by a function?
         | 
         | Why does useRef give you a thing used for attaching handles to
         | DOM elements so you can refer to them elsewhere, AND it gives
         | you an object whose .current property can be used as a variable
         | that persists without causing a render?
         | 
         | It's like someone complained that there were two many functions
         | in the API, and their names were too long, so they
         | overcorrected in the opposite direction.
        
           | madeofpalk wrote:
           | > Like, an componentDidMount event is a now useEffect with no
           | second argument?
           | 
           | Doesn't useEffect with no second argument run after _every_
           | render? componentDidMount 's equivalent is for an empty
           | dependency array in the second argument?
        
           | ajkjk wrote:
           | I love hooks, but I think they made a few mistakes. The
           | weirdness around useEffect having different behavior with no
           | second argument vs [] is one of them.
           | 
           | And they should have included a useUnloadEffect() by default,
           | even though it's trivial to write, just for clarity. It's way
           | too easy to miscount the number of ()s in useEffect(() => ()
           | => {}, []);
           | 
           | They also should have included a few other basic hooks, like
           | useStableValue() for just computing a constant once on first
           | render.
           | 
           | I hate the name `componentDidMount` though. useEffect seems
           | much better to me.
        
             | AgentME wrote:
             | It seems like almost always if you want to do anything
             | during unmount, it's cleaning up something you set up in a
             | useEffect call, which you also want to do any time the
             | useEffect call's dependency list changes, so it being part
             | of the useEffect hook helps programmers fall into the pit
             | of success. React's older class-based components had the
             | unmount handling separate (componentWillUnmount), and in my
             | experience on a large React codebase, many if not most
             | components using componentWillUnmount were subtly flawed
             | and failed to handle certain cases where props or state
             | updated in a way that should have caused effects to be
             | cleaned up or adjusted. React's useEffect hook way of
             | grouping up effects with their own cleanup code helps
             | people handle these cases correctly even without realizing
             | it sometimes.
        
             | kareemsabri wrote:
             | useRef is useStableValue
        
           | nickdandakis wrote:
           | You're translating the class-based way of working in React
           | against hooks, without stopping to consider understanding
           | hooks as a first-class principle instead of a translation.
           | 
           | It's called useEffect because it runs on the (side)effects
           | observed by the dependency array. An empty array happens to
           | happen on mount. useEffect returns a teardown function which
           | happens to correlate with unmount when an empty array is
           | passed.
           | 
           | It's called useRef because it returns a (mutable) reference
           | that's detached from the reactive layer. The DOM element
           | connection is just sugar.
           | 
           | I agree that useEffect has a lot of footguns, but this
           | position seems very shallow. The whole pattern changed, it
           | doesn't make a lot of sense to continue comparing the two
        
         | ajkjk wrote:
         | > e.g. I'm not sure how they're implemented
         | 
         | It might help to have a simple mental model for them?
         | 
         | Picture there is a global variable called _currentComponent:
         | _currentComponent: {         previousValue: React.Element
         | hooks: HookValue[]         currentHook: number
         | firstRender: boolean       }
         | 
         | Each HookValue is whatever that hook wants. For useState
         | something like:                 HookValue = {         hookName:
         | 'useState',         value: [state, setState],       }
         | 
         | Before your component is run, the renderer sets
         | `_currentComponent` to your component with its hooks set to
         | their current values.
         | 
         | If you run `useState(initial)` it looks like this:
         | function useState(initialValue) {         const component =
         | _currentComponent         let hookValue;         if
         | (firstRender) {           hookValue = {             hookName:
         | 'useState',             value: [initialValue, (newValue) => {
         | hookValue[0] = newValue               markForUpdate(component);
         | // some React-provided function to mark this as needing an
         | update             }           }
         | component.hooks[component.currentHook++] = hookValue;
         | return hookValue.value         } else {           hookValue =
         | component.hooks[component.currentHook++]
         | assert(hookValue.hookName == 'useState')           return
         | hookValue.value       }
         | 
         | Surely not perfect, but totally useable as a model of what's
         | going on. To be honest I wish React showed pseudocode like this
         | in the tutorials, it makes it a lot easier for me to
         | understand.
        
           | andyjohnson0 wrote:
           | Thank you for posting this.
        
           | acemarke wrote:
           | Yep! Also see Shawn Swyx Wang's talk "Getting Closure on
           | React Hooks", where he goes through an equivalent example in
           | more detail:
           | 
           | https://www.swyx.io/hooks/
        
       | acemarke wrote:
       | Josh's post is excellent!
       | 
       | Related, a couple years back I wrote a post on the same topic: "A
       | (Mostly) Complete Guide to React Rendering Behavior" [0]. It's
       | longer and has more details, but fewer diagrams :) (Josh's
       | ability to make interactive posts is amazing.)
       | 
       | I originally wrote my "Rendering Behavior" post specifically
       | because the existing React docs didn't clearly spell out this
       | kind of behavior, and I was _constantly_ seeing questions that
       | showed people didn't understand these concepts well. For example,
       | many folks assume that "React re-renders my component when its
       | props change", when in fact the real answer is that "React re-
       | renders recursively by default, _regardless_ of whether or not
       | any props changed". There's also a lot of confusion over how
       | Context ends up affecting renders, and I've seen folks end up in
       | situations where setting state in an "context provider" parent
       | component ends up rendering the _entire_ app - not because
       | Context changed, but because they did a `setState()` and that's
       | the natural behavior. So, I was trying to help clarify those
       | sorts of nuances.
       | 
       | I can say that it's been one of the top couple posts I've written
       | in terms of traffic and positive feedback (along with my "Redux
       | vs Context differences" post).
       | 
       | The good news is that the new React beta docs [1] _do_ cover at
       | least some of this rendering info, although it's more contextual
       | in various points of the explanations and in less detail. I'm
       | hopeful that after the main tutorial/API reference material is
       | done and the docs are opened up for external contributions, that
       | we can help add a couple pages that cover some of this rendering
       | behavior info as well.
       | 
       | There's a few other good articles I've also seen covering this
       | topic as well [2] [3] [4].
       | 
       | [0] https://blog.isquaredsoftware.com/2020/05/blogged-
       | answers-a-...
       | 
       | [1] https://beta.reactjs.org
       | 
       | [2] https://www.zhenghao.io/posts/react-rerender
       | 
       | [3] https://alexsidorenko.com/blog/react-render-cheat-sheet/
       | 
       | [4] https://www.developerway.com/posts/react-re-renders-guide
        
         | westoncb wrote:
         | I've been looking for something like your rendering behavior
         | article :) One question though: is it pretty up to date with
         | changes since 2020? (I think there were some things in React 18
         | that would affect rendering behavior--not sure though).
        
           | acemarke wrote:
           | Heh, unfortunately "update my rendering post to cover React
           | 18" has been on my todo list for _months_ now :)
           | 
           | As in, I literally have a todo list entry that I keep bumping
           | back until "Next Sunday", because other stuff is higher
           | priority. (like, trying to get Redux Toolkit 1.9 wrapped up
           | and shipped... and also playing as much golf as possible
           | while the weather is decent :) )
           | 
           | The shortest answer is that it's still effectively the same -
           | the one major change is that React 18 will now batch _all_
           | updates in _any_ given event loop tick, regardless of whether
           | those were queued up inside a React event handler or not.
           | 
           | There's a good discussion on this in the React 18 Working
           | Group post on "Automatic Batching":
           | 
           | https://github.com/reactwg/react-18/discussions/21
        
             | westoncb wrote:
             | Ah okay--no problem. Actually the only concrete rendering-
             | related thing I'd seen on React 18 was about the auto-
             | batching, so I'm already clear on the differences there. So
             | I'll still be giving the article a read--thanks for you
             | work on it, and enjoy the golf lol.
        
       | scyzoryk_xyz wrote:
       | I need to finally buy his CSS course - all the details in his
       | pages and materials are just gorgeous.
        
       ___________________________________________________________________
       (page generated 2022-08-16 23:00 UTC)