Monday, 30 January 2017

javascript - How to bind onclick handlers to `this` properly on React



Explanation to why this is not a duplicate: My code is already working, I have included as a comment. The question is why the this context change when I include it to click handler function.
I'm attempting a calculator project in React. The goal is to attach onclick handlers to number buttons so the numbers are displayed on the calculator display area. If the handler is written directly to render method it is working, however, if I'm trying from the ComponentDidMount I get an error this.inputDigit is not a function. How do I bind this.inputDigit(digit) properly?



import React from 'react';
import './App.css';


export default class Calculator extends React.Component {

// display of calculator initially zero
state = {
displayValue: '0'
}

//click handler function
inputDigit(digit){

const { displayValue } = this.state;
this.setState({
displayValue: displayValue+String(digit)
})
}

componentDidMount(){

//Get all number keys and attach click handler function
var numberKeys = document.getElementsByClassName("number-keys");

var myFunction = function() {
var targetNumber = Number(this.innerHTML);
return this.inputDigit(targetNumber); // This is not working
};
for (var i = 0; i < numberKeys.length; i++) {
numberKeys[i].onclick = myFunction;
}

}


render() {
const { displayValue } = this.state;
return (

{displayValue}





{/* This will Work*/}}
















)
}
}

Answer



Thats because you are writing it inside a function which is not bound,




Use



var myFunction = function() {
var targetNumber = Number(this.innerHTML);
return this.inputDigit(targetNumber);
}.bind(this);


or




const myFunction = () => {
var targetNumber = Number(this.innerHTML);
return this.inputDigit(targetNumber);
}


After this you need to bind the inputDigit function as well since it also uses setState



//click handler function

inputDigit = (digit) => {
const { displayValue } = this.state;
this.setState({
displayValue: displayValue+String(digit)
})
}


Since you want to use the button text as well, in that case you should use a separate variable in place of this to call the inputDigit function like






class Calculator extends React.Component {

// display of calculator initially zero
state = {
displayValue: '0'
}

//click handler function

inputDigit(digit){
const { displayValue } = this.state;
this.setState({
displayValue: displayValue+String(digit)
})
}

componentDidMount(){

//Get all number keys and attach click handler function

var numberKeys = document.getElementsByClassName("number-keys");
var that = this;
var myFunction = function() {
var targetNumber = Number(this.innerHTML);
console.log(targetNumber);
return that.inputDigit(targetNumber); // This is not working
};
for (var i = 0; i < numberKeys.length; i++) {
numberKeys[i].onclick = myFunction;
}


}

render() {
const { displayValue } = this.state;
return (

{displayValue}






{/* This will Work*/}















)
}
}


ReactDOM.render(, document.getElementById('app'))







No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...