0

Good day. I have the following problem: I have a class calculator and it changes state of firstOperand parameter on button click. But state doesn't change immediately, it changes the state of firstOperand only when I clicked one more button. Result is delay in 1 operation: I clicked 1 - indicator doesn't changed, I clicked 2 - indicator changed to 1, I clicked 5 - indicator changed to 12, etc. Here is part of my code:

    var Indicator = React.createClass({

        render: function () {
            return (
                    <div className="calc-indicator">
                        <input id="indicator" type="text" maxLength="20" size="20" value={this.props.value}/>
                    </div>
            );
        }
    });


    var Button = React.createClass({

        render: function () {
            return (
                    <div className="nav-button">
                        <button type="button" id={this.props.identifier} onClick={this.props.clickHandler}>
                            {this.props.digit}
                        </button>
                    </div>
            );
        }
    });


    var Calculator = React.createClass({

        setFirstOperand: function (value) {
            this.setState(
                    {
                        firstOperand: value
                    }
            );
            if (isDebug) {
                console.log("First operand state is set to " + value + ".");
            }
        },

        setSecondOperand: function (value) {
            this.setState(
                    {
                        secondOperand: value
                    }
            );
        },

        changeIndicator: function (value) {
            if (isDebug) {
                console.log("///Change indicator method is working///");
                console.log("change indicator parameter is " + value);
                console.log("first operand is " + this.state.firstOperand);
                console.log("second operand is " + this.state.secondOperand);
                console.log("operation is " + this.state.operation);
            }
            if (!value) { // if value hasn't been gotten
                value = '';

                if (this.state.firstOperand) {
                    value += this.state.firstOperand;
                } else {
                    value = '0';
                }
                if (this.state.operation) {
                    value += this.state.operation;
                }
                if (this.state.secondOperand) {
                    value += this.state.secondOperand;
                }
            }
            this.setState(
                    {
                        value: value
                    }
            );
            if (isDebug) {
                console.log("indicator is changed to " + value);
                console.log("/////////////////////////////////////");
            }
        },

        getInitialState: function () {
            calculator = this;
            return {
                firstOperand: null,
                secondOperand: null,
                operation: null,
                divisionByZero: false,
                value: '0'
            };
        },

        cipherClicked: function (event) {

            if (this.state.divisionByZero) {
                this.setDivisionByZero(false);
            }
            var newValue = event.target.innerHTML;
            var firstValue = this.state.firstOperand;
            var secondValue = this.state.secondOperand;
            var operation = this.state.operation;

            if (operation) {
                if (secondValue) {
                    secondValue = secondValue + newValue;
                } else {
                    secondValue = newValue;
                }
                if (isDebug) {
                    console.log("Second operand state is setting to " + secondValue + ".");
                }
                this.setSecondOperand(secondValue);
            } else {
                if (firstValue) {
                    firstValue = firstValue + newValue;
                } else {
                    if (newValue != 0) { // if indicator contains 0 and you have tried to add one 0 more
                        firstValue = newValue;
                    }
                }
                if (isDebug) {
                    console.log("First operand state is setting to " + firstValue + ".");
                }
                this.setFirstOperand(firstValue);
                setOperand(firstValue);
            }
            if (isDebug) {
                console.log("Calling changeIndicator function.");
            }

            this.changeIndicator();
        },


        render: function () {

            return (
                    <div id="calculator">
                        <table>
                            <tr>
                                <td colSpan="4">
                                    <Indicator value={this.state.value} />
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <Button identifier="MC" digit="MC" clickHandler={this.memoryNavigationClicked}/>
                                </td>
                                <td>
                                    <Button identifier="MR" digit="MR" clickHandler={this.memoryNavigationClicked}/>
                                </td>
                                <td>
                                    <Button identifier="M+" digit="M+" clickHandler={this.memoryNavigationClicked}/>
                                </td>
                                <td>
                                    <Button identifier="M" digit="M" clickHandler={this.memoryNavigationClicked}/>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <Button identifier="BS" digit="BS" clickHandler={this.editNavigationClicked}/>
                                </td>
                                <td>
                                    <Button identifier="CL" digit="CL" clickHandler={this.editNavigationClicked}/>
                                </td>
                                <td>
                                    <Button identifier="C" digit="C" clickHandler={this.editNavigationClicked}/>
                                </td>
                                <td>
                                    <Button identifier="negate" digit="+-" clickHandler={this.negateClicked}/>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <Button identifier="7" digit="7" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="8" digit="8" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="9" digit="9" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="divide" digit="/" clickHandler={this.operationClicked}/>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <Button identifier="4" digit="4" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="5" digit="5" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="6" digit="6" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="multiply" digit="*" clickHandler={this.operationClicked}/>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <Button identifier="1" digit="1" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="2" digit="2" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="3" digit="3" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="minus" digit="-" clickHandler={this.operationClicked}/>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <Button identifier="0" digit="0" clickHandler={this.cipherClicked}/>
                                </td>
                                <td>
                                    <Button identifier="dot" digit="." clickHandler={this.dotClicked}/>
                                </td>
                                <td>
                                    <Button identifier="eq" digit="=" clickHandler={this.operationClicked}/>
                                </td>
                                <td>
                                    <Button identifier="plus" digit="+" clickHandler={this.operationClicked}/>
                                </td>
                            </tr>
                        </table>
                    </div>
            );
        }
    });

    React.render(<Calculator />, document.body);

</script>
</body>
</html>

1 Answers1

0

As per my React Native answer here, setState can be an asynchronous operation, not synchronous. This means that updates to state could be batched together and not done immediately in order to get a performance boost. If you really need to do something after state has been truly updated, there's a callback parameter:

this.setState({ searchString: event.nativeEvent.text }, function(newState) {
    console.log('Changed State');
    console.log('searchString = ' + this.state.searchString);
}.bind(this));

It’s also mentioned in the React Documentation.

Community
  • 1
  • 1
Colin Ramsay
  • 16,086
  • 9
  • 52
  • 57