React: how to reset state

I have a problem: basically, my calculator, as it is, allows concatenation of operators (eg, you can input “±”). My idea to fix this was to set up a different state for the operators and then reset this state everytime the input enters an operator. I can´t get it to run, though. I tried declaring the function outside of the handleclick event, no dice either.

class Calculator extends Component {
  constructor(props) {
    super(props);
    this.state = {value:"",
    operators:""}
  this.handleClick = this.handleClick.bind(this);
      }



  handleClick(evt){
 const id=evt.target.id;
 const result= evt.target.value;






  if(id === ('add' || 'subtract' || 'multiply' || 'divide') ) {
 resetState(){
return this.setState({operators :""})
};
this.setState({
      operators: this.state.operators + result
    })
}






this.setState(prevState => ({
  value: `${prevState.value}${result}`.replace(/^0+\B/, "")
}));

if(id==="equals"){
    this.setState({value: math.eval(this.state.value)})
}
else if(id==="clear"){
this.setState({value : 0})  
 }

}



render() {
    return(
            <div id="container">
                <Display value={this.state.value} />
                <Button onClick={this.handleClick} id="zero" value={'0'} />
                <Button onClick={this.handleClick} id="one" value={'1'} />
                <Button onClick={this.handleClick} id="two" value={'2'}/>
                <Button onClick={this.handleClick} id="three" value={'3'} />
                <Button onClick={this.handleClick} id="four" value={'4'} />
                <Button onClick={this.handleClick} id="five" value={'5'} />
                <Button onClick={this.handleClick} id="six" value={'6'} />
                <Button onClick={this.handleClick} id="seven" value={'7'} />
                <Button onClick={this.handleClick} id="eight" value={'8'}  />
                <Button onClick={this.handleClick} id="nine" value={'9'} />
                <Button onClick={this.handleClick} id="decimal" value={'.'} />
                <Button onClick={this.handleClick} id="equals" value={'='} />
                <Button onClick={this.handleClick} id="clear" value={'clear'}  />
                <Button onClick={this.handleClick} id="add" value={'+'} />
                <Button onClick={this.handleClick} id="subtract" value={'-'} />
                <Button onClick={this.handleClick} id="multiply" value={'*'} />
                <Button onClick={this.handleClick} id="divide" value={'/'} />
            </div>
)

}
}

The answer doesn’t like in code: It’s about what the program needs, so English/pseudocdoe is what we need:

Whats the problem? We can enter two successive operators
Is that a problem for other types of input? No, because numeric /[0-9|.]/ input can follow itself, with the exception that there can’t be two decimal places in the same numeric input token
So, what behavior do we want We want only the last operator token to remain in the string after the last numeric input.
Does that solve all the issues with input? Well, we have that decimal input thing.

So, it looks like there are two targets to implement. The how is up to you. Minimal changes to your existing code (in the part of handleClick() with that multi-OR boolean test) can be effected. You currently have 2 calls to this.setState, but are only actually running one, whose return value is not useful anyway. But that function exits after the first line.

HINT: One way is to use a Regex, as hinted implicitly above.

1 Like

Remember that in JavaScript to chain multiple statements into one if statement we have to have a new item to compare to for each comparison.

So instead of if (this == that || that2 || that3) we need if (this == that || this == that2 || this == that3)

Good luck!

2 Likes

@TheEternalDoubter: To ping off of what Jordan said, if you have that many if statements, you should consider using a switch statement (or an object for lookup of callbacks that actually run the code).

EDIT: I’m wrong. If you have multiple conditions you are OR’ing together, a utility function can lead to clarity:

const isOperator = (btn) => btn === 'add' || btn === 'subtract' || btn === 'multiply' || btn === 'divide';
2 Likes

Thank you both for the answers. I am a bit confused, though, because I got this answer off stackoverflow:

"So basically you are trying trying to set state for “operators” in the scope of “if” statement and expecting the updated value in the same scope. Also, since setState is async and you are returning from resetState function, the setState following it is called with older value of this.state.operators"

I will use a Regex just like I did with the zero, that´s for sure. But, I mean, why was my approach wrong to begin with?

Not your approach, but your implementation. You’re checking the event.target.id property of the button that got clicked, which tells you if an operator key was clicked. That’s fine. What you’re not checking is what I said with the middle question:

We want only the last operator token to remain in the string after the last numeric input.

You need to check for whether an operator was the LAST thing entered, and act differently based on the result of that conditional test.

[EDIT]: I’m leaving the house now, so I won’t be able to respond right away. Not ghosting you.

1 Like

Thank you. But I mean: wouldn´t resetting and updating state be a viable solution? Since checking for the last entered input in React is, as far as I know at least, impossible.

There’s lots of solutions to the same problem. And depending on your implementation it absolutely could work.

And as far as your comment earlier:

this is also a common problem. It’s not “wrong” but it almost always doesn’t give you what you want. Typically the state won’t be updated instantly and not until after the whole function has been run.

Thank you for the reply. But, in my scenario, wouldn´t the reset function run first?

Nope, it’s not guaranteed. React works in weird ways. But what you could do is instead of trying to reset it to null and then add the result, you could just overwrite the state.

So instead of:

this.setState({
      operators: this.state.operators + result
    })

its:

this.setState({
      operators: result
    })

Since you were trying to reset operators to null anyways, “” + result will always just be result, and this way you don’t have to worry about state not having been reset first.

2 Likes

Thank you. So make a function that returns that and add it to the conditional, basically?

Don’t even need a function. Just replace it inside your existing handleClick

1 Like

Okay…So it would be (if id=whatever) {
this.setState({
operators: result
})
That would reset the input everytime the user enters it?

Yep.

Or to make your life easier do a switch statement and set state in the same statement. Save yourself some typing

Well, that does sort of work: it does stop one from inputting two operators. But it also deletes all previous values.
So I can either use a RegEx or stores the values somewhere else.

Rereading through your posts, I thought that is what you wanted to do.

If not, what functionality are you trying to accomplish?

I want to stop the user from entering two consecutive (and equal) operators. Right now, whenever an user enters a “-” (used that one for testing purposes), it gets displayed as “–” with the possibility of accumulating even more. I basically want the operators state to reset (and log just one) everytime someone enters an operator.

And with our changes, does it not do that?

If you press the add button, it sends the value of add to the function which gets stored in result. We then want addition to be the current operator so we set the state of operator to add.

Is this not the functionality we are wanting?

My code was wrong: you are right.
But now I need a way to store the values entered before the operators.

What if you had a flag that changed when the operator button was pressed, and when the flag is off it stores the numbers in one variable as the first number (before operator pressed) and another after it is pressed when the flag is on?

You got this!