React: Unbound method better than bound?

Hello.

Following the technique used in the FreeCodeCamp React course, when I use methods inside a class component, I usually do this:

class MyClass-1 extends Component {

    constructor(props) {
    	super(props)
        this.state = {
           count: 0
        }
        this.generate = this.generate.bind(this)
    }

    generate(){
        this.setState((prevState) => {
            return {
                count: prevState.count + 1
            }
        })
    }

    render(){
        return(
            <div>
                ...
            </div>
        )
    }
}

i.e. I bind the method in the constructor: this.generate = this.generate.bind(this)

However, I’ve also found this way of doing it (based on a bit of someone else’s code):

class MyClass-2 extends Component {

    constructor(props) {
    	super(props)
        this.state = {
           count: 0
        }
    }

    generate = ()=> {
        this.setState((prevState) => {
            return {
                count: prevState.count + 1
            }
        })        
    }

    render(){
        return(
            <div>
                ...
            </div>
        )
    }
}

Here, generate is assigned to an arrow function and there is no need to do any binding in the constructor.

This means less code, but is this (second) method safe?

Stage 3, would have been part of the language this year but they put it back so that private class fields could be included as part of it.

You don’t need the constructor at all in your example, just do

class Example {
  state = {
    count: 0
  };

  generate = () => {
    this setState({ count: this state.count + 1 })
  };


  ...
}

Is it safe to use in browsers as-is? No, because it isn’t part of the language so it won’t work. But barring some unforseen weirdness it will be part of the language next year. So is it safe to use with transpiled code (ie code put through Babel)? Yes.

Also note hooks exist and let you do the same thing without classes and without any non-standard JS.

Hi thanks.

I thought this.state = {...} always had to be inside a constructor - along with super() … !

It’s is this.state if it’s a class property.

Once you are using class properties, it is only really useful inside the constructor if you need to do some setup work before defining it. Similarly, you only need super(props) if you intend to do some setup work using the props, as it’s the only way you can access them before the constructor function runs to completion. React doesn’t often need setup logic in the constructor; it has lifecycle methods that are generally more useful. And once there is no setup logic, the constructor becomes useless and can be dropped in most cases.

I see!

Not doubting what you say in the least but I am wondering why both the React courses I’ve done say that you have to have constructor + super.

Also not quite sure what you mean by state is only really useful inside the constructor if some setup work is required beforehand. The word used in the courses is ‘initialisation’.

So, in my example I’ve initialised ‘count’ in this.state = {count:0}. Isn’t that correct?

Personally, I prefer the first one. using this.X.bind(this); I have had some troubles when using a function and at the same time unmounting the component.

pd: I didn’t know the React.Component could be dropped in most cases; ty, Dan.

So you’re saying that:

class MyClass {
...
}

is all that’s required, and not:

class MyClass extends React.Component {
...
}

?

No, you have to extend component, i was just writing a simplified version as an example, sorry for confusion

If you need to use this inside the constructor you need to use super. Once you have class fields, you don’t need to do that, so you don’t need super. And if the constructor takes no arguments and does no extra work (ie it looks like constructor() {}), it’s not needed, JS will automatically do that for you.

I just mean that if you are in an environment where you have access to class fields (eg you are compiling using Babel and you have the correct plugin to allow class properties), then you can use them.

And by setup, I mean if you need to take the existing props and use them to build parts of the state, rather than just defining some keys/values. The following are almost exactly the same:

class Example {
  constructor () {
    this.state = { count: 0 };
  }
}
class Example {
  state = { count: 0 };
}

It’s totally fine, it’s just that if you can use class fields, then it makes sense to use them for stuff like state. And for handlers (otherwise you need to use bind to get around JS’ this wierdnesses).

The point is that you can avoid the cognitive (and literal processing overhead) of using bind to capture the scope of this. You just define the function as a normal arrow function and it works, it’s a lot more ergonomic, not least because you only now need to define the function once.

Edit:

Without class fields in the language, you have to write super(props), this.state etc, and bind methods you want to pass down as props. This is all generally annoying and can introduce subtle errors, class fields kinda remove the annoyance and simplify things –https://overreacted.io/why-do-we-write-super-props/

1 Like

Thanks very much for your incredibly detailed response. And for that useful link at the end :slight_smile:

1 Like

If you’re working on React stuff, do have a read through all of his posts – some of them are a bit technical, but they’re generally extremely clear as to benefits and downsides of various approaches. Dan Abramov is an excellent technical writer. There’s a good argument to be made that Redux (he is the author of that library) is as popular as it is in large part because he enunciated the benefits of it so well.