Live data from Hacker News

Why React Re-Renders

joshwcomeau.com

61–70 of 168 posts

Re: Why React Re-Renders

#61

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 im…

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, "componentDidMo…

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

Re: Why React Re-Renders

#62

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 im…

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, "componentDidMo…

> 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?

Re: Why React Re-Renders

#63

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 ex…

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.…

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.

Re: Why React Re-Renders

#64

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 im…

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.

Re: Why React Re-Renders

#65
post #56

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 ma…

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

Re: Why React Re-Renders

#66

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 _constan…

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).

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

Re: Why React Re-Renders

#67

Earlier quoted context omitted.

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.…

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…

> 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?

Re: Why React Re-Renders

#68
post #15

Earlier quoted context omitted.

What would they be using instead?

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.

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.

Re: Why React Re-Renders

#69
post #29

Earlier quoted context omitted.

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

>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…

"Rules of hooks" is a thing.

Re: Why React Re-Renders

#70

Earlier quoted context omitted.

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).

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 effe…

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.
Post reply on HN