0

I am bit puzzled as when to to bind in constructor and when not to it .I tried reading two codes but couldn't get to a conclusion as when bind is needed ? I need an explanation on the basis of two codes .

    class Calculatetop extends React.Component{
    constructor(props){
        super(props);

        this.state = this.initialState();
        this.operatorStack = [];
        this.operandStack = [];
        this.shouldReset = false;
    }

    initialState() {
      return {
          currentDisplay:'',
        };
    }

    reset() {
      this.setState(()=> this.initialState());
      this.operatorStack = [];
      this.operandStack = [];
    }

    handleInput(input) {

      let digits = ["0","1","2","3","4","5","6","7","8","9","."];
      let operators = ["+","-","*","/","="];

      if (input === "C") {
        this.reset();
        return;
      }

      if (digits.includes(input)) {
        console.log("input is "+input);
        if(this.shouldReset === true) {
           this.state.currentDisplay = '';
           this.shouldReset = false;
        }
        this.setState({
          currentDisplay : this.state.currentDisplay + input

        })

      }

      if (operators.includes(input)) {
       console.log(this.operandStack);
       console.log(this.operatorStack);
      if(this.operatorStack.length > 0 && this.precedence(input) <= this.precedence(this.topOperator()) || input == "=") {
        console.log("inside if ");
        this.operandStack.push(parseFloat(this.state.currentDisplay));
        console.log("this.state.currentdisplay"+this.state.currentDisplay);

        this.solveStack();
        let result = this.operandStack[0];
        this.setState({
          currentDisplay:`${result}`
        })
        if(input=="="){
        this.operandStack = [];
        this.operatorStack = [];
        }
      } else {
        console.log("else part executed");


        this.operandStack.push(parseFloat(this.state.currentDisplay));
      }


        if (input !== '=') {
          this.operatorStack.push(input);
          this.shouldReset = true;
        }

      }

    }

    topOperator() {
      return this.operatorStack[this.operatorStack.length - 1];
    }

    solveStack() {
      console.log("solvestack is executed");
      while(this.operatorStack.length > 0) {
        console.log(this.operandStack);
        let operator = this.operatorStack.pop();
        let operandTwo = this.operandStack.pop();

        let operandOne = this.operandStack.pop();
        this.operandStack.push(this.performOperation(operandOne,operandTwo,operator));
      }
    }

    precedence(operator) {
      return {
        '+' : 1 , '-' : 1 , '*' : 2 , '/' : 2
      }[operator];
    }

    performOperation(first,second,operator) {
      if (operator === "+") {
        return first + second;
      }
      else if (operator === "-") {
        return first - second;
      }
      else if (operator === "*") {
        return first * second;
      }
      else if (operator === "/") {
        return first / second;
      }
    }

    render()
    {
        return(
         <div>
             <h1>CalculatorApp</h1>
             <CalculatorDisplay
             currentDisplay={this.state.currentDisplay}
             ></CalculatorDisplay>
             <CalculatorConfig inputHandler={(input) => this.handleInput(input)}></CalculatorConfig>
             </div>

        );
    }
}

Here is the second code and I see bind being heavily used in this class but I couldn't understand as why we need to use this in second code .

class Indecisionapp extends React.Component{
    constructor(props){
        super(props);
        this.handledeleteoptions=this.handledeleteoptions.bind(this);
        this.handlepick=this.handlepick.bind(this);
        this.handleaddoption=this.handleaddoption.bind(this);
        this.state ={
            options:[]
        };
    }
    handledeleteoptions(){
        this.setState(()=>{
            return{
              options:[]
            };
        });

    }
    handlepick(){
    const randomnum=Math.floor(Math.random() *this.state.options.length);
    const option=this.state.options[randomnum];
    alert(option);
    console.log(randomnum);
    }
    /// it takes an argument
    handleaddoption(option){
      console.log(option);
      if(!option){
          return 'Enter valid text';
      }
      else if(this.state.options.indexOf(option)>-1){
          return 'the option already exits ';
      }
      this.setState((prevState)=>{
        return{
          options:prevState.options.concat([option])
        };
    });

    }
    render(){
       const titlevar="Indecision App";
        const subtitlevar='Put your life in the hands of a computer';
        //const optionsvar=['one ','two','three'];
       return(

        <div>
            <Header title={titlevar} subtitle={subtitlevar}/>
            <Action 
            hasoptions={this.state.options.length>0}
            handlepick={this.handlepick}
            />
            <Options 
            options={this.state.options}
            handledeleteoptions={this.handledeleteoptions}
            />
            <Addoptions
            handleaddoption={this.handleaddoption}
            />
            </div>

       );

    }
}
jammy
  • 857
  • 2
  • 18
  • 34
  • Suggested reading: https://blog.andrewray.me/react-es6-autobinding-and-createclass/ – Andy Ray Jan 23 '18 at 18:29
  • Possibly this answer addresses your concern https://stackoverflow.com/questions/41113798/why-and-when-do-we-need-to-bind-functions-and-eventhandlers-in-react/41113862#41113862 – Shubham Khatri Jan 23 '18 at 18:32
  • @ShubhamKhatri My concern is when not to bind. – jammy Jan 23 '18 at 18:38
  • If you understand when to bind then you will surely know when not to. As a matter of fact you only need bind when you want to access something from react component context – Shubham Khatri Jan 23 '18 at 18:59

2 Answers2

0

One way to know if you need to bind (or use the new () => {}) syntax is if the context would switch. A few examples of this are in event handlers, or if you are passing the function as an argument. One way to just get rid of binding though is to use the newer (ES6) syntax for creating a function. One quick example would be:

export default class ButtonWrapper extends React.Component {
    handleClick = (e) => {
        this.props.handleClick(e);
    }
    render() {
        return (
            <button onClick={this.handleClick}>Button!</button>
        );
    }
}
iHowell
  • 2,263
  • 1
  • 25
  • 49
0

Binding is typically needed when passing the method to a child component via a prop, as it will be called inside the scope of that object, which changes the value of this to reference the calling object.

You can either bind in the class's constructor or bind when the method is passed as a prop. It's considered best practice to bind in the constructor because, if you bind as you are passing it as a prop, a new method reference will be created every time the child component is rendered, potentially slowing down performance.

The other option is to use an arrow function when defining your class methods, () => {} which preserves the scope to the defining object, no matter where the method is passed.

Example:

class Foo extends React.Component {
  constructor(props) {
    this.boundMethodOne = this.boundMethodOne.bind(this)
  }

  boundMethodOne() {
    return 'bound in constructor!'
  }

  boundMethodTwo() {
    return 'bound in prop!'
  }

  unboundMethod() {
    return this.hello()
  }

  arrowMethod = () => {
    return 'bound by nature!'
  }

  hello() {
    return "I'm inside Foo!"
  }

  _privateMethod() {
    return this.hello()
  }

  render() {
    console.log(this._privateMethod()) // doesn't need to be bound because it's not being passed anywhere
    return (
      <Bar 
        boundMethodOne={this.boundMethodOne}
        boundMethodTwo={this.boundMethodTwo.bind(this)}
        unboundMethod={this.unboundMethod}
        arrowMethod={this.arrowMethod} />
    )
  }
}

class Bar extends React.Component {
  hello() {
    return "I'm inside Bar!"
  }

  render() {
    console.log(this.props.boundMethodOne()) // => bound in constructor!
    console.log(this.props.boundMethodTwo()) // => bound in prop!
    console.log(this.props.unboundMethod()) // => I'm inside Bar!
    console.log(this.props.arrowMethod()) // => bound by nature!
  }
}
Levi V
  • 78
  • 1
  • 7