Live data from Hacker News

Why React Re-Renders

joshwcomeau.com

51–60 of 168 posts

Re: Why React Re-Renders

#51

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…

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.

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

Re: Why React Re-Renders

#53

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, "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.

Re: Why React Re-Renders

#54

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…

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

Re: Why React Re-Renders

#55
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.

Re: Why React Re-Renders

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

Re: Why React Re-Renders

#57

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…

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.

Re: Why React Re-Renders

#58
post #6
post #5

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?

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.

If you want a job, learn react

Re: Why React Re-Renders

#59

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

Re: Why React Re-Renders

#60

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

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.

Post reply on HN