Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Explaining why we bind things in React

Start With This

Before getting to React, it's helpful to know what this does generally in Javascript. Take the following snippet of code. It's written in ES6 but the principles for this predate ES6.

class Dog {
  constructor() {
    this.favoriteWord = "Woof!";
  bark() {
    return this.favoriteWord;

let dog = new Dog();
dog.bark(); // => Woof!

Cool. That makes sense. But remember, functions are also objects in their own right in Javascript, so let's try this:

let bark = dog.bark;
bark(); // => Error

Ruh roh. What happened? You probably got a message saying favoriteWord wasn't a property of undefined, or something similar. But this.favoriteWord clearly refers to the Dog instance, so what gives?

The answer is that this is determined at the time the function is called, not the time the function is defined. This can be super confusing if you're coming from, say, Python, where the following code works:

class Dog:
  def __init__(self):
    self.favorite_word = "Woof!"
  def bark(self):
    return self.favorite_word;

dog = Dog()
bark = dog.bark
bark() # => Woof!

It's tempting to say this and self do the same things. They both refer to the parent of a function in this case. But in the case of Python, self is determined at the time the function is defined. In the case of Javascript, this is determined at the time the function is called.

The bark variable is distinct from dog.bark. To make this a little clearer, let's just use a different name.

let bark2 = dog.bark;

We're creating a new variable (bark2). bark2 doesn't have a parent at the time it's called, unlike dog.bark (which has dog as a parent). bark2 is a top level variable, so it's "parent" is undefined. undefined doesn't have a favoriteWord property, so calling the function results in an exception.

Before a Javascript expert shouts at me, note that in Javascript-land, we generally think of the relationship between dog and bark not as "parent" and "child", but that dog is the "context" for bark. dog.bark means "Call the bark function with the context of dog". And this always refers to the context in a given function.

To understand why someone (if not necessarily you or me) might think this is cool, consider the following:

let cat = {
  favoriteWord: "Meow!"
cat.meow = bark;
cat.meow(); // => "Meow!"
bark();     // Nope, still broken

This works because the this variable in the bark function isn't tied to the original dog object. So we can freely assign bark to cat.meow. And when we call cat.meow, the caller is cat, so this.favoriteWord refers to "Meow!" instead of "Woof!".

As an aside, the "context" for a Javascript function or class method is distinct from "context" in React. As the React developers themselves indicate, if you're just getting started with React, ignore React's version of context. However, you do need to understand context in the Javascript sense insofar that you're using classes to represent React components and invoking stuff like this.props or this.setState({ ... }).


OK, let's add a new wrinkle. Consider this now:

let alwaysWoof = bark.bind(dog);
alwaysWoof(); // => "Woof!"

Why does this work? It's because calling bind on a function returns a copy of that function in which this is always set to whatever arg you pass to bind. This applies even if we change the caller of the bound function:

cat.meow = alwaysWoof;
cat.meow(); // => "Woof!"

In the class context, it's pretty common to bind to this:

class ConsistentDog {
  constructor() {
    this.favoriteWord = "Woof!";
    let bark = function() {
      return this.favoriteWord;
    this.bark = bark.bind(this);

let conDog = new ConsistentDog();
let conBark = conDog.bark;
conBark(); // => "Woof!"

Writing .bind(this) over and over is pretty annoying, so in ES6, you can also avoid writing .bind(this) with the () => ... syntax:

class SimpleDog {
  constructor() {
    this.favoriteWord = "Woof!";
    this.bark = () => this.favoriteWord;
      Or you can do this if you need more than one statement 
      for your function.
      this.bark = () => {
        let simpleWord = this.simpleWord;
        return simpleWord;

let simDog = new SimpleDog();
let simBark = simDog.bark;
simBark(); // => "Woof!"

Now with React Classes

Still with us? OK, now to bring in React. Consider this React component, defined as an ES6 class:

class Welcome extends React.Component {
  render() {
    return <button onClick={this.sayName}>Say My Name</button>;
  sayName() {

In React, you invoke like this: <Welcome name="Bob" />. This renders a button. Clicking the button should trigger an alert with "Bob".

Except it doesn't. Because in the above example, this would be undefined in the sayName function.

What's happening inside the render function is that this refers to the current instance of our React component. That component has a sayName function defined, so this.sayName points to our function, just fine and dandy.

But what React is doing behind the scenes is assigning this.sayName to another variable. That is, it's just like this:

let onClick = this.sayName;
onClick(); // Technically a click event is passed to onClick
           // but this doesn't matter for our purposes

And just like our dog example, we get an error. Because this is undefined. This is extra confusing because in previous versions of React, React would "autobind" the event handler for you, so it would work. But at some point, Facebook decided to stop doing that, so ... here we are.

So how can we fix our component? We just do binding ourselves, like this:

<button onClick={this.sayName.bind(this)}>Say My Name</button>;

Or with ES6 syntax:

<button onClick={() => this.sayName()}>Say My Name</button>;

And it should work!

One final note -- when we bind a function in React, we can do that not only when the render function is called, but before as well. So take this:

class Welcome extends React.Component {
  constructor(props) {
    this.boundSayName = this.sayName.bind(this);

  render() {
    return <button onClick={this.boundSayName}>Say My Name</button>;
  sayName() {

We can do this.boundSayName instead of this.boundSayName.bind(this). Because this.boundSayName was already bound to this in the constructor.

And that's it! Hope it helps!

Copy link

clpud commented Nov 18, 2019

Thanks a lot!

Copy link

dariushine commented Mar 9, 2020

Very helpful, thanks man!

Copy link

ravij3 commented May 21, 2020

Thanks a lot!

Copy link

enochychang commented Jun 13, 2020

This is super

Copy link

minweny commented Sep 8, 2020

It helps a lot. You are my life saver!

Copy link

ecolss commented Nov 15, 2020

Awesome post, cleared my confusion!

Copy link

j4hangir commented Dec 8, 2020

Beautiful mess, as always, in JS 😄

Copy link

zhangbanghui commented Jan 6, 2021

thanks a lot!

Copy link

carlos-ch commented Mar 29, 2021

Excelent! Thanks a lot!

Copy link

Amanporwal510 commented Apr 21, 2021

Beautifully Amazing!! what a article man hats off to you!!

Copy link

heyaoliu666 commented Jul 29, 2021

Thanks a lot, I am stucked in this problem for 2 days until see your answer. Very clear and helpful!

Copy link

kibrukuture commented Jan 28, 2022

nice post, cleared the confusion I had. thanks a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment