Stuck on React Javascript Calculator

Stuck on React Javascript Calculator
0

#1

Hello everyone,
I am currently working on the Javascript Calculator for the Front End Libraries. I’ve got a rough layout for the buttons and display, but I’m stuck on getting the on click function to change the value in display based on the buttons presses. Any help would be appreciated. Thanks!

My codepen


#2

I’m still learning React, but let me take a stab.

When I inspect the elements, none of them actually have the onClick attribute tied to a function. Since you are using react, perhaps you should go revisit the relevant challenges and review them to see how to properly add an eventhandler to a tag. So far, I don’t see any bind functions, nor constructors in your React class Components.


#3

I should have clarified. I have applied the onClick for only the number 1 and the clear button at the moment. Also this component you are look at is the Calculator component which is a child to the App Component I add further down. This is why I didn’t add a constructor. I used a similar method for my drum machine and it worked but I’m not sure what’s wrong with this.


#4

Which is fine. But again, I don’t see any of the buttons having a onclick attribute, even on the 1 and C button. This leads me to believe that you have set up the components improperly.

Still, I’m sorry I am not experienced to help you. Just, those were my impressions.


#5

The onclick event is working - you can test this by putting an alert as the first line in the handleClick().

This won’t work outside of a constructor method:

this.state = this.intialState;

You need to use setState to force the re-rendering to happen:

Hope that helps! Learn more about the lifecycle methods as well.


#6

Below is one possibility and gets rid of all those if else statements.

Note 1: Code below does not include the buttonBank array to save space.

Note 2: I changed the Calculator component name to Button, because that is what you are actually rendering in the child component.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      display: 0
    };
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick(id, symbol) {
    const currDisplay = this.state.display;
    const toDisplay = id === 'clear' ? 0 : !currDisplay ? symbol : currDisplay + '' + symbol;
    this.setState({
      display: toDisplay
    });
  }    
  
  render() {
    const buttons = buttonBank.map(({id,symbol}) => <Button key={id} handleClick={this.handleClick} id={id} symbol={symbol} />);
    return (
      <div className="container" id="calculator">
        <div id="display">
          <h1> {this.state.display} </h1>
        </div>
        <div id="calc-buttons">
          {buttons}
        </div>
      </div>
    );
  }
}

class Button extends React.Component {
  render() {
    return (
      <div className="calc-button">
        <button
          id={this.props.id}
          onClick={this.props.handleClick.bind(this, this.props.id, this.props.symbol)}
        >{this.props.symbol}</button>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

#7

I did not comment the code, so if you have any questions about what I wrote, definitely ask.


#8

Thanks for all the help guys! Yeah I have a question about how you used bind on the onClick for the button class. You performed the standard bind but then you added more arguments . How does that work?


#9

I figured you might wonder about that one. The bind method’s first agrument provides the context for this. Any additional arguments passed will be arguments passed to the function being bound. In this case, I needed to pass the id and symbol, so the handleClick function in the parent could use those.


#10

Another approach which involves two main changes to the previous code I suggested is seen below. One difference is instead iterating through the buttonBank array to create Button components, I pass a Buttons component with only the clickHandler method passed as a prop. The iteration of the buttonBank is handled by the Buttons component which now is a Stateless Functional Component which displays the buttons.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      display: 0
    };
  }
  
  handleClick(id, symbol) {
    const currDisplay = this.state.display;
    const toDisplay = id === 'clear' ? 0 : !currDisplay ? symbol : currDisplay + '' + symbol;
    this.setState({
      display: toDisplay
    });
  }    
   
  render() {
    return (
      <div className="container" id="calculator">
        <div id="display">{this.state.display}
          <Buttons handleClick={this.handleClick.bind(this)} />
        </div>
      </div>
    );
  }
}

const Buttons = ({handleClick}) => {
  const buttons = buttonBank.map( ({id,symbol}) => (
    <div key={id} className="calc-button">
      <button
        id={id}
        onClick={handleClick.bind(this, id, symbol)}
      >{symbol}</button>
    </div>
  ));
  
  return (
    <div id="calc-buttons">{buttons}</div> 
  );
}

ReactDOM.render(<App />, document.getElementById("root"));