Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Getting Started

Brendan Whiting
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Brendan Whiting
Front End Web Development Techdegree Graduate 84,735 Points

Understanding `.bind(this)` and arrow functions.

We have this code in the video where we are binding the function to this.

onKeyDown={this.handleChange.bind(this)}

I'm trying to wrap my head around what's going on here. Is the first this referring to the same thing as the 2nd this? Is this part of the problem that is solved by arrow functions, and if so, how would we refactor this code to take advantage of that? Here is the full code:

// Libs
import React, { Component } from 'react';
import { render } from 'react-dom';

// CSS
import './css/style.css';

// Component
class GuestList extends Component {
  constructor() {
    super(...arguments);
    this.state = {
      names: [
        { name: 'Joel' },
        { name: 'Alena' },
        { name: 'Andrew' },
        { name: 'Thera' }
      ]
    }
  }

  handleChange(event) {
    if(event.key == 'Enter') {
      let newName = { name: event.target.value }
      let newNames = this.state.names.concat(newName);
      event.target.value = '';
      this.setState({ names: newNames });
    }
  }

  handleRemove(i) {
    var newNames = this.state.names;
    newNames.splice(i, 1);
    this.setState({ names: newNames });
  }

  render() {    
    let guests = this.state.names.map((name, i) => (
      <li key={name.name}>
        {name.name}
        <button onClick={this.handleRemove.bind(this, i)}>Remove</button>
      </li>
    ));

    return (
      <div className="guest-list">
        <h1>Guest List</h1>
        <input type="text" placeholder="Invite Someone" value={this.state.newName} onKeyDown={this.handleChange.bind(this)} />
        <ul>

          {guests}

        </ul>  
      </div>
    );
  }
}

render(
  <GuestList />, 
  document.getElementById('root')
);

1 Answer

Stephan L
Stephan L
17,821 Points

That's a good question, and a common point of confusion. Requiring .bind() in this case goes back to the concept of prototypal inheritance. In this case, React is creating new instances of the class when it renders, so exactly which 'this' you are referring to can get lost. From the spec:

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. >If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

The spec also suggests that you bind a method's 'this' in your constructor function, so a better way to write it might be:

   constructor() {
    super(...arguments);
    this.state = {
      names: [
        { name: 'Joel' },
        { name: 'Alena' },
        { name: 'Andrew' },
        { name: 'Thera' }
      ]
    }
this.handleChange = this.handleChange.bind(this);   //this way, this is bound to the parent, not every new instance of the class
  } 

This is actually a situation where arrow functions would not be appropriate, since arrow functions don't lexically bind 'this' the way regular functions do. So you'd run into the same problem if you tried to call the event later. The JavaScript docs specify that because they don't lexically bind, arrow functions wouldn't be appropriate for method functions, for the same reasons.

Hope that makes sense.

Brendan Whiting
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Brendan Whiting
Front End Web Development Techdegree Graduate 84,735 Points

Cool. What's up with the other spot in the code where we bind this and also an index variable?

<button onClick={this.handleRemove.bind(this, i)}>Remove</button>
Seth Kroger
Seth Kroger
56,413 Points

That's something called functional currying, which is where you create a higher-order function where one or more of the arguments are filled in. Here because data like the index to remove won't normally get passed along with the click event, it's using bind to create a copy of handleRemove() with the value filled in already.