Understanding "this" in React
Tags: javascript, react
Published: 2019-07-26 04:51:50

> PS - This was originally post in my [blog](https://akhilaariyachandra.com/understanding-this-in-react/ "Understanding 'this' in React"). Check it out if you want learn more about React and JavaScript!

`this` in JavaScript can confusing as it can change based on where it is called from. In this post I'll try to clear it up.

> The JavaScript "this" keyword refers to the object it belongs to. [^1]

To clearly understand how `this` can change let's look at the places it can be called from.

## "this" alone

```javascript
const test = this
console.log(test) // global variable
```

`this` accessed outside a function will return the global variable.

## "this" in a function

```javascript
function foo() {
  console.log(this) // undefined in “strict mode” or the global variable
}
```

If we access `this` inside a function (cannot be a method), it'll be the global variable and in "strict mode" it'll be `undefined`.

## "this" in a method

```javascript
const user = {
  firstName: "Akhila",
  lastName: "Ariyachandra",
  fullName: function() {
    return this.firstName + " " + this.lastName
  },
}

console.log(user.fullName()) // Akhila Ariyachandra
```

When `this` is accessed in a method, it refers to the owner of the method, which is the object it's in.

### "this" in an inner function

```javascript
const user = {
  firstName: "Akhila",
  lastName: "Ariyachandra",
  fullName: function() {
    return this.firstName + " " + this.lastName
  },
  innerFunction: function() {
    function testFunction() {
      return this.firstName + " " + this.lastName
    }

    return testFunction()
  },
}

console.log(user.innerFunction()) // undefined undefined
```

Here `this` changes inside `testFunction()`. In order to understand why we need to know how scope applies to `this`.

> Unlike variables, the this keyword does not have a scope, and nested functions do not inherit the this value of their caller. If a nested function is invoked as a method, its this value is the object it was invoked on. [^2]

This means that the `this` of `testFunction()` is not aware of the `user` object so it returns `undefined` for `this.firstName` and `this.lastName`.

### So how do we get the proper "this" into the inner function?

#### Before ES5

```javascript
const user = {
  firstName: "Akhila",
  lastName: "Ariyachandra",
  innerFunction: function() {
    const that = this
    function testFunction() {
      return that.firstName + " " + that.lastName
    }

    return testFunction()
  },
}

console.log(user.innerFunction()) // Akhila Ariyachandra
```

Before _ES5_ there was no proper way to pass `this` to inner functions. The example shown around is a workaround. [^3]

### ES5

```javascript
const user = {
  firstName: "Akhila",
  lastName: "Ariyachandra",
  innerFunction: function() {
    function testFunction() {
      return this.firstName + " " + this.lastName
    }

    testFunction = testFunction.bind(this)

    return testFunction()
  },
}

console.log(user.innerFunction()) // Akhila Ariyachandra
```

_ES5_ introduced the `bind` method, which allows us to set the `this` of the function. So after we run the line `testFunction = testFunction.bind(this)`, the `this` of `testFunction()` becomes the `user` object.

### ES6+

```javascript
const user = {
  firstName: "Akhila",
  lastName: "Ariyachandra",
  innerFunction: function() {
    const testFunction = () => {
      return this.firstName + " " + this.lastName
    }

    return testFunction()
  },
}

console.log(user.innerFunction()) // Akhila Ariyachandra
```

_ES6_ brought us **arrow functions**, which automatically binds `this` to the function, which leads to less and cleaner code.

## So what about React?

Consider the following code.

```jsx
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: "",
    }
  }

  setText() {
    this.setState({ text: "Hello World!" })
  }

  render() {
    return (
      <div>
        <h1>{this.state.text}</h1>
        <button onClick={this.setText}>Set Text</button>
      </div>
    )
  }
}
```

It'll fail once we click the button and code reaches the `this.setState({ text: "Hello World!" });` line. Why? Because at that point `this` will be `undefined`. `this` wasn't implicitly bound to `setText()` so it defaults to the global variable which in this case is `undefined` because classes run in "strict mode". Since `this` wasn't implicitly bound, we need to explicitly bind `this` to `setText()`.

We could solve this by using the way we did it the before _ES5_ example but that's stringly discouraged. If we did it with `bind`, it would look like this.

```jsx
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: "",
    }
    this.setText = this.setText.bind(this)
  }

  setText() {
    this.setState({ text: "Hello World!" })
  }

  render() {
    return (
      <div>
        <h1>{this.state.text}</h1>
        <button onClick={this.setText}>Set Text</button>
      </div>
    )
  }
}
```

If you use `bind`, you'll have to do it in the constructor.

Arrow functions can make it easier by just needing to change `setText()` to an arrow function.

```jsx
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: "",
    }
  }

  setText = () => {
    this.setState({ text: "Hello World!" })
  }

  render() {
    return (
      <div>
        <h1>{this.state.text}</h1>
        <button onClick={this.setText}>Set Text</button>
      </div>
    )
  }
}
```

## References

[^1]: w3schools.com, [The JavaScript this Keyword](https://www.w3schools.com/js/js_this.asp).
[^2]: David Flanagan, JavaScript: The Definitive Guide
[^3]: amitai, [Using "this" in react functions](https://gist.github.com/amitai10/adb66d6faa714e8c3cdb94946bb98356)