Fixing isseus with THIS in React

class Car {

	setDriveSound(sound){
  this.sound = sound
  }
  drive(){
  return this.sound;
  }
}

const car = new Car();
car.setDriveSound('vroom');


const drive = car.drive;

drive()

above code is broken as this is undefined

in legacy react it would be solved by adding a constructor that binds this to this 🙂

class Car {
  constructor(){
  this.drive = this.drive.bind(this);
  }
	setDriveSound(sound){
  this.sound = sound
  }
  drive(){
  return this.sound;
  }
}

const car = new Car();
car.setDriveSound('vroom');


const drive = car.drive;

drive()

Another example:

import React from "react";
class SearchBar extends React.Component {
  state = { term: "" };

  onFormSubmit(event) {
    event.preventDefault();
    console.log(this.state.term);
  }
  render() {
    return (
      <div className="ui segment">
        <form onSubmit={this.onFormSubmit} className="ui form">
          <div className="field">
            <label htmlFor="searchfield">Search term</label>
            <input
              name="searchfield"
              type="text"
              placeholder="fill in your searchterm"
              value={this.state.term}
              onChange={(e) => this.setState({ term: e.target.value })}
            />
          </div>
        </form>
      </div>
    );
  }
}

export default SearchBar;

When trying to hit enter, we get back “TypeError: Cannot read property ‘state’ of undefined

the reason being that this function

  onFormSubmit(event) {
    event.preventDefault();
    console.log(this.state.term);
  }

equals to

  onFormSubmit: function(event) {
    event.preventDefault();
    console.log(this.state.term);
  }

and whenever the function keyword is what causes the issues with THIS.

Great news! ARROW functions automatically binds the value of this for all the code inside of the function.
So we can fix the issue that this returns undefined by replacing the function with an arrow function:

import React from "react";
class SearchBar extends React.Component {
  state = { term: "" };

  onFormSubmit = (event) => {
    event.preventDefault();
    console.log(this.state.term);
  };
  render() {
    return (
      <div className="ui segment">
        <form onSubmit={this.onFormSubmit} className="ui form">
          <div className="field">
            <label htmlFor="searchfield">Search term</label>
            <input
              name="searchfield"
              type="text"
              placeholder="fill in your searchterm"
              value={this.state.term}
              onChange={(e) => this.setState({ term: e.target.value })}
            />
          </div>
        </form>
      </div>
    );
  }
}

export default SearchBar;

//the arrow function makes sure the value of this is always the same as our instance of the Searchbar

Finally there is a third way to solve this issue>

import React from "react";
class SearchBar extends React.Component {
  state = { term: "" };

  onFormSubmit(event) {
    event.preventDefault();
    console.log(this.state.term);
  }

  render() {
    return (
      <div className="ui segment">
        <form
          onSubmit={(event) => this.onFormSubmit(event)}
          className="ui form"
        >
          <div className="field">
            <label htmlFor="searchfield">Search term</label>
            <input
              name="searchfield"
              type="text"
              placeholder="fill in your searchterm"
              value={this.state.term}
              onChange={(e) => this.setState({ term: e.target.value })}
            />
          </div>
        </form>
      </div>
    );
  }
}

export default SearchBar;

Add your comment