Reputation: 239
I am trying to build React calculator. So far it works only if the length of my second number is equal to 1. if it's more digits it's gonna break. Here is the code:
class Calculator extends Component {
constructor(props) {
super(props);
this.state = {
current: 0,
total: 0,
operator: ''
};
}
handleType = (e) =>{
const current = (this.state.current == 0 || this.state.operator != '' || this.state.current == this.state.total ) ? '' : this.state.current
this.setState({
current: parseInt(current + e.target.attributes.getNamedItem('data-filter').value)
});
}
calculate = (sign, number) => {
const total = this.state.total;
console.log(total);
switch(sign){
case "-":
return total - number;
break;
case "+":
return total + number;
break;
case "*":
return total * number;
break;
case "/":
return total / number;
break;
default:
return 0;
}
};
handleAction = (e) =>{
const operator = e.target.attributes.getNamedItem('data-filter').value;
console.log(operator);
this.setState({
total: this.state.current,
operator: operator
});
console.log(this.state);
}
getResult = () =>{
this.setState({
current: this.calculate(this.state.operator, this.state.current)
});
}
render() {
return (
<div className="Calculator text-center">
<h2>Result: {this.state.current} </h2>
<div className="row">
<button data-filter="7" onClick={this.handleType}>7</button>
<button data-filter="8" onClick={this.handleType} >8</button>
<button data-filter="9" onClick={this.handleType} >9</button>
<button data-filter="+" onClick ={this.handleAction} >+</button>
</div>
<div className="row">
<button data-filter="4" onClick={this.handleType}>4</button>
<button data-filter="5" onClick={this.handleType}>5</button>
<button data-filter="6" onClick={this.handleType}>6</button>
<button data-filter="-" onClick ={this.handleAction} >-</button>
</div>
<div className="row">
<button data-filter="1" onClick={this.handleType}>1</button>
<button data-filter="2" onClick={this.handleType}>2</button>
<button data-filter="3" onClick={this.handleType}>3</button>
<button data-filter="*" onClick ={this.handleAction} >*</button>
<button data-filter="/" onClick ={this.handleAction} >/</button>
</div>
<div className="row">
<button>0</button>
<button>save</button>
<button>cancel</button>
<button onClick={this.getResult}>=</button>
</div>
</div>
);
}
}
I understand that the problem is my condition:
const current = (this.state.current == 0 || this.state.operator != '' || this.state.current == this.state.total ) ? '' : this.state.current
It works fine for the first number, when operator='' but once I have an operator it will not allow me to make my number greater than 9.
Here is the codepen demo http://codepen.io/polinaz/pen/PmLoKJ?editors=0010
Any ideas how to fix it? Thank you:)
Upvotes: 1
Views: 1709
Reputation: 2152
I've made a number of changes in your code:
As State Updates can be Asynchronous (https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous), it's very bad practise to use previous state values in the way you are using:
this.setState({
current: parseInt(current + e.target.attributes.getNamedItem('data-filter').value)
});
I have change a number of these into this format:
this.setState((prevState) => {
const current = prevState.current;
return {current: parseInt(current + value)};
});
I moved the e.target.attributes.getNamedItem('data-filter').value
code into it's own variable due to event-pooling
handleType (e) {
const value = e.target.attributes.getNamedItem('data-filter').value;
The major bug you were facing was, after the Operator was selected (via handleAction
), your operator attribute was populated. This mean in your handleType
, you did the check: this.state.operator != ''
const current = (this.state.current == 0 || this.state.operator != '' || this.state.current == this.state.total ) ? '' : this.state.current
This meant you were disregarding the previously selected current value. setting it to '' and then appending it to the the current value.
class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = {
current: 0,
total: 0,
operator: ''
};
this.handleType = this.handleType.bind(this);
this.calculate = this.calculate.bind(this);
this.handleAction = this.handleAction.bind(this);
this. getResult = this.getResult.bind(this);
}
handleType (e) {
const value = e.target.attributes.getNamedItem('data-filter').value;
this.setState((prevState) => {
const current = (this.state.current == 0 || this.state.current == this.state.total ) ? '' : this.state.current;
return {current: parseInt(current + value)};
});
}
calculate (sign, number) {
const total = this.state.total;
console.log(total);
switch(sign){
case "-":
return total - number;
break;
case "+":
return total + number;
break;
case "*":
return total * number;
break;
case "/":
return total / number;
break;
default:
return 0;
}
};
handleAction (e) {
const operator = e.target.attributes.getNamedItem('data-filter').value;
this.setState((prevState) => {
return {
total: prevState.current,
operator: operator,
current: 0
}
});
console.log(this.state);
}
getResult () {
this.setState({
current: this.calculate(this.state.operator, this.state.current)
});
}
render() {
return (
<div className="Calculator text-center">
<h2>Result: {this.state.current} </h2>
<div className="row">
<button data-filter="7" onClick={this.handleType}>7</button>
<button data-filter="8" onClick={this.handleType} >8</button>
<button data-filter="9" onClick={this.handleType} >9</button>
<button data-filter="+" onClick ={this.handleAction} >+</button>
</div>
<div className="row">
<button data-filter="4" onClick={this.handleType}>4</button>
<button data-filter="5" onClick={this.handleType}>5</button>
<button data-filter="6" onClick={this.handleType}>6</button>
<button data-filter="-" onClick ={this.handleAction} >-</button>
</div>
<div className="row">
<button data-filter="1" onClick={this.handleType}>1</button>
<button data-filter="2" onClick={this.handleType}>2</button>
<button data-filter="3" onClick={this.handleType}>3</button>
<button data-filter="*" onClick ={this.handleAction} >*</button>
<button data-filter="/" onClick ={this.handleAction} >/</button>
</div>
<div className="row">
<button data-filter="0" onClick={this.handleType}>0</button>
<button>save</button>
<button>cancel</button>
<button onClick={this.getResult}>=</button>
</div>
</div>
);
}
}
ReactDOM.render(
<Calculator/>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'></div>
Upvotes: 1
Reputation: 104379
Did some changes, refer the snippet.
Working snippet:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = {
current: '',
total: 0,
operator: ''
};
}
handleType = (e) =>{
const current = (this.state.current == 0 || this.state.operator != '' || this.state.current == this.state.total ) ? '' : this.state.current
this.setState({
current: this.state.current + e.target.attributes.getNamedItem('data-filter').value
});
}
calculate() {
const total = parseInt(this.state.total);
const current = parseInt(this.state.current);
const sign = this.state.operator;
switch(sign){
case "-":
return total - current;
break;
case "+":
return total + current;
break;
case "*":
return total * current;
break;
case "/":
return total / current;
break;
default:
return 0;
}
};
handleAction = (e) =>{
const operator = e.target.attributes.getNamedItem('data-filter').value;
this.setState({
total: this.state.current,
current: '',
operator: operator
});
}
getResult = () => {
this.setState({
total: this.calculate(),
current: ''
});
}
cancel = () => {
this.setState({
total: '',
current: '',
operator: ''
})
}
render() {
return (
<div className="Calculator text-center">
Number: {this.state.current}
<h2>Result: {this.state.total} </h2>
<div className="row">
<button data-filter="7" onClick={this.handleType}>7</button>
<button data-filter="8" onClick={this.handleType} >8</button>
<button data-filter="9" onClick={this.handleType} >9</button>
<button data-filter="+" onClick ={this.handleAction} >+</button>
</div>
<div className="row">
<button data-filter="4" onClick={this.handleType}>4</button>
<button data-filter="5" onClick={this.handleType}>5</button>
<button data-filter="6" onClick={this.handleType}>6</button>
<button data-filter="-" onClick ={this.handleAction} >-</button>
</div>
<div className="row">
<button data-filter="1" onClick={this.handleType}>1</button>
<button data-filter="2" onClick={this.handleType}>2</button>
<button data-filter="3" onClick={this.handleType}>3</button>
<button data-filter="*" onClick ={this.handleAction} >*</button>
<button data-filter="/" onClick ={this.handleAction} >/</button>
</div>
<div className="row">
<button data-filter="0" onClick={this.handleType}>0</button>
<button>save</button>
<button onClick={this.cancel}>cancel</button>
<button onClick={this.getResult}>=</button>
</div>
</div>
);
}
}
ReactDOM.render(<Calculator/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'>
Upvotes: 1