Skip to content

Brady Mackey

Understanding `this` in React

Javascript, React6 min read

When I first started learning React, I was always confused that for some reason React didn't understand that I had to use this everywhere. I had to bind this when I called a function, or used this.state, this.props, this.handleClick; you name it, you had to consider this and what it meant in the context of whatever you did.

At first, I thought this was because React was poorly designed. In reality, its a function of the way that JavaScript implements classes. For React to diverge would be both a ton of work, and remove flexibility from the framework. This my attempt at explaining how I understand this, but hopefully with the context of how to use it within React.

Preface: Don't just read this post

I stand on the shoulders of giants in terms of my understanding of javascript, scope, and this. I highly recommend that in addition to playing with these concepts yourselves in REPLs and your code base, explore the learning options out there. I personally have learned a lot of this material on Frontend Masters with a particular shoutout for Kyle Simpson and Will Sentance for making absolutely phenomenal courses that were not only fun to watch and participate in but were immensely helpful in solidifying foundation knowledge of javascript.

Why does this exist in the first place?

Before you can under this in React, you have to understand what this is in vanilla JavaScript

Javascript variables are static or "lexically" scoped. When javascript gets compiled, it bases what variables a block of code has access to based on where it is defined in the code. Lexical is another word for "written", so it matters where a variable is defined.

In a function, you don't just have access to variables in your functions local scope, you also have access to variables up the "lexical scope chain". If you define a function fn2 within a function fn1, then fn2 will be able to use any variable defined in it own local variable environment and anything in fn1's environment.

1function fn1() {
2 var foo = 'foo';
3 var bar = 'bar';
4 function fn2() {
5 var bar = 'bar';
6 var bam = 'bam';
7 }
8}

In this contrived example, fn2 would be able to access all four variables at run time, but fn1 would only be able to access foo and bar. fn2 resides within fn1 so it can see variables up the chain, but fn1 can't look for variables down the chain.

What if I don't know what the variable will have at compile time? Maybe you want to write a method that will reference data on an object the method is defined on. In this case you need to dynamically determine the scope at execution time, and for that, you are going to need this.

What is 'this'

Even MDN doesn't provide a great definition for what this is. It is hard to boil down to a single defition, and there are always caveats. This is my best attempt at defining what this is...

this in javascript will by default reference the object which invoked the function

That doesn't sound so hard, except when you consider that sometimes you can use bind to make it bound to a new function, you can use arrow functions that won't define their own this context, you can use call or apply to change how this interacts with your code. Ultimately, it can be quite tricky to figure out what this actually is.

How do I use 'this'

The simplest way to use this is to reference some kind of property on an object inside a of function defined on that object. Lets consider the an example Student named Brady...

1var Brady = {
2 name: 'Brady',
3 grades: ['A','B',...],
4 changeName: function(newName) {
5 this.name = newName;
6 },
7}

In this example, our changeName property is a function that changes the name of the Student object to be a new name.

1console.log(Brady.name); //Brady
2Brady.changeName("Bill");
3console.log(Brady.name); //Bill

Great! I have a Brady Object and I can change the name on the object. This implementation means I need to manually create the all my students. Lets work towards a function that can create students

How does this all relate to classes

JavaScript is a prototypal language. Being a prototypal language means a lot of things, but one of the major consequences is that JavaScript did not originally have an implementation of Classes or Inheritance. But you could make something that looked very much like a class using the objects and function. Lets see how we might make a Student.

1var studentFunctions = {
2 changeName: function(newName) {
3 this.name = newName;
4 },
5}
6
7function studentCreator(name, grades) {
8 var newStudent = Object.create(studentFunctions);
9 newStudent.name = name;
10 newStudent.grades = grades;
11 return newStudent;
12}
13
14var brady = studentCreator('Brady', ['A','B']);
15var bill = studentCreator('Bill', []);

We have defined a function that "creates" students. It attaches the functions we want on every student to a new Object with Object.create. It then attaches the properties that will define that particular student from the arguments to the creator function, and then returns the newly created student.

You probably won't see classes written like this in JavaScript. This is definitely a lot of code, but what is happening is obvious. When you call studentCreator, you are making a new object with the properties of studentFunctions, assigning the inputs to properties on that object, and then returning it. But developers are by nature lazy, so they wanted to automate this. To streamline this process, you can use the new keyword. new will do 4 things.

  1. Create a brand new Object
  2. Create a link between that new Object's prototype and the prototype of the function that called it
  3. Execute the function and pass the newly created Object into the function as the this context
  4. If the function doesn't return anything, returns this from the function

That lets you take our above code and make it into something that looks like this...

1function Student(name, grades) {
2 this.name = name;
3 this.grades = grades;
4}
5
6Student.prototype.changeName = function(newName) {
7 this.name = newName;
8}
9
10var brady = new Student('Brady',['A','B'])
11var bill = new Student('Bill', [])

This is fewer lines of code and is much more declaritive. But if you don't understand whats happening under the hood, then the behavior you get might feel odd.

This is how javascript creates classes, which are defined by properties and methods on an Object. When you are using this inside of these classes, you are ultimately trying to reference the this that is that Object. You want to get to the variable state you put on the Object, you have to get it with this.state. You want to access the handleChange you defined as a property as this.handleChange. And most importantly inside those functions you need this to reference that class Object so that you can do all the wonderful things you want to do with your React Components

But I'm using classes, not Objects!

In Javascript, class is just syntactic sugar for using the exact same notation that I specified above. You could also write a student class like this.

1class Student {
2 constructor(name, grades) {
3 this.name = name;
4 this.grades = grades;
5 }
6
7 changeName(newName) {
8 this.name = newName;
9 }
10}

classes have a couple extra bits (like the super keyword) but for most cases, they are the exact same thing. This syntax is easier to write, and has a ton of advantages. But its largest disadvantage is that its very easy to create a class in javascript and have no idea how it works under the hood, which can lead to misunderstanding and bugs down the line.

When are you gonna talk about React already!

To understand this in React, you have to understand this in plain old javascript.

A long time ago, React added functionality to use the native ES6 class to make a React component. For better or for worse they chose to not auto-bind this, and instead implemented classes the same as ES6 would.

So largely, it is on you to bind the right this context to your functions so that they can access the this that has all the properties like setState, state, and anything else you define on the class Object. If you don't, then when you go update the state, or change anything on this, your function will fail as this will be undefined.

How to bind this to your functions

One of the things that I don't like about React is just how many different ways there are to bind this. I think that it leads to confusion about what is happening and where the this binding is actually occuring. I'm going to try and detail all the ways that I know how to bind this, and hopefully that should give you a good idea of how you might see it happening.

But just as important as examples are understanding the tools that are used to bind this, and that means that we need to talk about regular functions, arrow functions and the bind keyword...

Aside: Arrow Functions

ES6 made a new syntax for functions that looks like this.

1var printHey = () => console.log('hey')

Its called an arrow function. In this case, that arrow function is equivalent to this function expression.

1var printHey = function() {
2 return console.log('hey')
3}

So whats the difference? That can be illustrated with another object.

1this.name = "Bill"
2
3myCoolObject = {
4 name: "Brady",
5 printArrow: () => {
6 console.log(this.name)
7 },
8 printReg() {
9 console.log(this.name)
10 }
11}
12
13myCoolObject.printArrow() //Bill
14myCoolObject.printReg() //Brady

It looks like these two functions do the same thing, but they actually print different things to the console. Why?

Arrow functions don't define their own this context, they inherit it from the lexical scope. Function declarations bind their this context from the object that they are defined on. So printReg gets this.name from myCoolObject, but printArrow gets this.name from the environmnet where myCoolObject is defined.

If a function doesn't use this, then there is no difference between arrow and function declarations. But this subtle difference allows us to use arrows to define functions in React without binding then like normal function declarations.

Binding this in React

Here is a brief summary of how I have seen people commonly bind this...

this could be bound to the function in the constructor.

1class Button extends React.Component {
2 constructor() {
3 ...
4 this.toggle = this.toggle.bind(this);
5 }
6
7 toggle() {
8 ...Some dope logic using this
9 }
10
11 render() {
12 ...type up some sweet sweet JSX
13 <RandomThing toggleProp={this.toggle} />
14 }
15}

Or you can define the function as an arrow function on the class.

1class Button extends React.Component {
2 constructor() {
3 ...
4 }
5
6 toggle = () => {
7 ...Some dope logic using this
8 }
9
10 render() {
11 ...type up some sweet sweet JSX
12 <RandomThing toggleProp={this.toggle} />
13 }
14}

But which is better?

That is really up to preference. I used to prefer bind(this) because it was more explicit. Today I prefer arrow functions because they are more common and reduce noise. Each has its place. But whats more important than how you bind this in your React components is understanding why you have to do it in the first place. A deeper undersanding of lexical and relative scoping in variables is valuable no matter what you are programming in JavaScript.

2020 Update

I originally wrote this article in 2018. How time flies when it comes to React. I used to spend hours teaching students about this in React, and now you don't have to worry about it at all because Functional Components are far more common than Class Components. You probably won't need to do a lot of binding in todays React. But much of this is about this in general, rather than the specific case of React, so I hope that you can still glean some useful bits of knowledge.