简体   繁体   中英

React: How to force setState()?

In this React Javascript Calculator this.setState({ array: displayed}); is supposed to update the array in state, but it doesn't. Is there a way to force it? Any help would be greatly appreciated.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';


class JavascriptCalculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: 0,
      array: [],
      operators:['+']
    }
    this.display = this.display.bind(this);
    this.clear = this.clear.bind(this);
    this.calculate = this.calculate.bind(this);
  }

  display(text){
    // if display is zero, remove the leading zero from the text.
    if(this.state.text == 0){
      this.state.text = ''
    }

    let regex = /[*/+-]/;

    // if text is not an operator
    if (!regex.test(text)){

      let displayed = this.state.text
      // disallow consecutive decimal points
      if (text == '.' && displayed.slice(-1) == '.'){
        return;
      }

      // start by adding text
      displayed = this.state.text += text;

      // disallow multiple decimal points in a number
      // if attempt at more than one decimal point remove last one.
      let array = displayed.split('');
      let count = 0;
      for (let i = 0; i < array.length; i++){
        if (array[i] == '.'){
          count++;
        }
      }
      // one decimal point is allowed per operator.
      // thus to allow the first decimal point,
      // this.state.operators must be initialized
      // to length of 1.
      if(count > this.state.operators.length){
        array.pop();
      }
      displayed = array.join('');
      this.setState({ text: displayed});
    }

    // if text is an operator
    if (regex.test(text)){
      // add the text to the array
      // so that repeated decimal points are prevented
      let array = this.state.operators;
      array.push(text);
      this.setState({ operators: array});

      // add the text to the text
      let displayed = this.state.text += text;
      this.setState({ text: displayed});
    }

    // if text ends in equals sign, run the calculate function.
    if (text == '='){
      let displayed = this.state.text.split('');

      console.log(displayed);
      this.setState({ array: displayed});
      //this.state.array = displayed;
      this.calculate();
    }
  }

  calculate(){
    let regex = /[*/+-]/;
    let text = '';
    let length = this.state.array.length;
    let operators = [];

    //console.log(this.state.array);

    // capture numbers longer than one digit by adding them to a string
    // and adding a comma in place of the operators, so the string
    // can be split into an array at the operators.
    for (let i = 0; i < length; i++){
      // put numbers into a string
      if (this.state.array[i].match(/[\d.]/)) {
        text+=this.state.array[i];
      }
      // add commas to string in place of operators
      if (this.state.array[i].match(regex)){
        text+=',';
      // add operators to their own array
        operators.push(this.state.array[i]);
      }
      if (this.state.array[i] == '='){
        break;
      }
    }

    //console.log(operators);
    // create the numbers array
    let numbers = text.split(',');
    //console.log(numbers);

    // initialize answer with first number
    let answer = numbers[0];
    let func = undefined;

    // Start with second number
    for (let i = 1; i < numbers.length; i++){

      func = returnFunc(operators.shift());
      console.log(func);
      answer = func(answer, numbers[i]);
    }

    this.display(answer);

    function returnFunc(val) {
      switch (val) {
        case '+':
        return function sum(a,b) { return Number(a)+Number(b)};
        case '-':
        return function subtract(a,b) { return Number(a)-Number(b)};
        case '*':
        return function multiply(a,b) { return Number(a)*Number(b)};
        case '/':
        return function divide(a,b) { return Number(a)/Number(b)};
        default:
        throw new Error("Called with unknown operator " + val);
      }
    }
  }

  clear(id){
    this.setState({ text: id });
    this.setState({ array: [] });
    this.setState({ operators: [] });

  }

  render() {
    return (
      <div id="javascript-calculator">
      <h1 id="title">Javascript Calculator</h1>
      <div id="display">{this.state.text}</div>
      <hr/>
      <div>
      <button id="clear" onClick={e => this.clear("0")}> clear </button>
      <button id="equals" onClick={e => this.display("=")}> = </button>
      <button id="zero" onClick={e => this.display("0")}> 0 </button>
      <button id="one" onClick={e => this.display("1")}> 1 </button>
      <button id="two" onClick={e => this.display("2")}> 2 </button>
      <button id="three" onClick={e => this.display("3")}> 3 </button>
      <button id="four" onClick={e => this.display("4")}> 4 </button>
      <button id="five" onClick={e => this.display("5")}> 5 </button>
      <button id="six" onClick={e => this.display("6")}> 6 </button>
      <button id="seven" onClick={e => this.display("7")}> 7 </button>
      <button id="eight" onClick={e => this.display("8")}> 8 </button>
      <button id="nine" onClick={e => this.display("9")}> 9 </button>
      <button id="add" onClick={e => this.display("+")}> + </button>
      <button id="subtract" onClick={e => this.display("-")}> - </button>
      <button id="multiply" onClick={e => this.display("*")}> * </button>
      <button id="divide" onClick={e => this.display("/")}> / </button>
      <button id="decimal" onClick={e => this.display(".")}> . </button>
      </div>
      </div>
    );
  }
}

ReactDOM.render(<JavascriptCalculator />, document.getElementById("app"));

index.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <title>Javascript Calculator</title>
  <style>
  </style>
</head>
<body>
  <main>
    <div id="app"></app>
    </main>
  </body>
  </html>

setState is async. It won't work how you're using it. In your case, you should just pass the displayed array to the calculate function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM