0

I was reading an article (link) about the difference between functional and class components. The article links to a sandbox which is what this question refers to (link).

In the article, we have this class component:

class ProfilePage extends React.Component {
  showMessage = () => {
    alert('Followed ' + this.props.user);
  };

  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };

  render() {
    return <button onClick={this.handleClick}>Follow</button>;
  }
}

This component is rendered in a parent component that passes it a user prop. If you click on the button, and then change the user in the parent component, the alert that shows up will display the "incorrect" user, ie it will display the current value of the user prop, not the one that was current when the button was clicked. I don't understand why this is.

The article explains it as:

This class method reads from this.props.user. Props are immutable in React so they can never change. However, this is, and has always been, mutable.

Indeed, that’s the whole purpose of this in a class. React itself mutates it over time so that you can read the fresh version in the render and lifecycle methods.

First, I see that class methods are being used, but aren't props available on the instance (ie the React element, which is a JS object instance)? I probably have an incorrect understanding here of how React is actually functioning under the hood.

Second, the class methods are being used to be able to have this be the Component itself (ie the JavaScript class). Again, my doubt about where props are actually stored. I thought it was on the instance, the generated React element.

Third, with the above answers I might be able to answer this but: what does React mutate over two renders? I thought it was the particular JS object (React element) that is the result of calling render.

Edit:

1) So the "class methods" I mentioned are "Class fields", and this is syntactic sugar for defining the fields on this in the constructor. So in fact these methods belong to the instances.

2) The "class methods" are defined as arrow functions, so when they are actually placed on this in the constructor, they are bound to what this is in the constructor.

3) Therefore, yes, props are on an instance, but the question for me remains: We have one particular object with a set of props, and it sets the setTimeout to call this.showMessage; then I guess React replaces this with a new version of the object, but why does the this on the callback on the original object change?

evianpring
  • 3,316
  • 1
  • 25
  • 54
  • Custom properties on the class are not tied to the React lifecycle. making a change to a `this.users` (or whatever it is called) property wont update the view. Use `state` to map data to your view. – John Ruddell Jul 16 '19 at 23:08
  • it's actually `this.props.users` that I have there, and I'm updating this prop from a parent component. – evianpring Jul 16 '19 at 23:12
  • yea on the parent what is it? – John Ruddell Jul 16 '19 at 23:21
  • On the parent it is state. – evianpring Jul 16 '19 at 23:26
  • can you post the parent then? you are updating state on parent and its not re-rendering on the child? sounds like you are not updating something correctly – John Ruddell Jul 16 '19 at 23:28
  • I linked to the codesandbox in the beginning of my question. I just saw that it is actually Dan Abramov's codesandbox and article, so I think this is not a question of the code being incorrect, it is my understanding of the code that I need an answer to. – evianpring Jul 16 '19 at 23:32
  • Maybe this will help you? https://stackoverflow.com/a/48210686/2030321 – Chris Jul 16 '19 at 23:43
  • @Chris Thanks, that was informative, but I am changing the title of my question to better reflect what I actually want to know: Why is a class component method passed to setTimeout in a class component not necessarily bound to the same `this` when it gets executed as when it was passed to setTimeout? – evianpring Jul 17 '19 at 00:03
  • @evianpring despite reading this a few times, I don't fully understand your question. As pointed out in my linked answer, objects are passed by reference, not by value. Thus, if you trigger the timeout and change the value of `user` before the callback of the timeout is executed, then the alert will show the "new" value of `user`. The callback is executed when the timer expires, nothing happens before then. – Chris Jul 17 '19 at 00:13
  • @Chris Yes, indeed I do get that. But in the given explanation, why does he say that "This class method reads from this.props.user. Props are immutable in React so they can never change. However, this is, and has always been, mutable." I mean, I would understand if the reference to a new props object is now being referenced on `this`, but why does he say that `this` is what React mutates? – evianpring Jul 17 '19 at 00:40
  • Didnt read the article except for the paragraph you quoted. Perhaps you are reading into it a bit too much :) – Chris Jul 17 '19 at 00:43
  • Its probably because you are creating the handler function each render cycle. So the value during the setup that is going to be used is the function reference created in that render cycle. The class handles it correctly because the handler function reads from the prop value as a more persistent function. I haven't been a fan of hooks tbh, it doesn't feel like its following the ES standards and or the direction the standards have been going – John Ruddell Jul 17 '19 at 00:59

0 Answers0