首页 > 解决方案 > React-Redux:并非所有调度都出于某种原因工作

问题描述

下面是一个简单的,未完成的计算器应用程序,我已经包含了上下文的整个代码,为了澄清名称,该应用程序使用了 Redux 中的 4 个主要状态属性currentNumber,这是当前显示和修改的数字display, mirror,除了几个边缘情况外,currentNumber 的副本镜像到 display, memory顶行的右侧部分或末端,它位于同一顶行中的镜像左侧并延伸每当按下算术运算符时,和calcState,这是计算器的当前“状态”,与我的问题密切相关,我使用 calcState 使数学结果后第一次按下按钮的行为略有不同。简而言之,该应用程序只是创建一个可计算的字符串并使用 eval() 执行它,并且功能不完整,不是问题的一部分。

现在问题出现在第 171 行或在 CalcButton React 组件的handleClick函数内部,我附在此处。预期行为是,当按下计算器上的 '=' 按钮并计算结果时(参见案例“equals”),将 Redux 的 calcState 属性更改为“solved”,从而为下一次按下按钮启用特殊行为,然后将 calcState 属性重置为“正常”。这可以在函数的最顶部看到,但是在if(this.props.calcState=="solved")语句中发生了一些非常奇怪的事情。

handleClick(event) {
      
      if(this.props.calcState=="solved") {
        this.props.changeMemory(this.props.currentNumber)
        this.props.changeCurrentNumber("0");
        this.props.changeMirror("");
        this.props.changeCalcState("normal");
      }
      
    switch(event.target.className) {
      case "digit":
        let digit = event.target.value;
        if(this.props.currentNumber=="0") {
          this.props.changeCurrentNumber(digit);
          this.props.changeMirror(digit);
        }
        else if(this.props.currentNumber==".") {
          this.props.changeCurrentNumber("0."+digit);
          this.props.changeMirror("0."+digit);
        }
        else {
        this.props.changeCurrentNumber(this.props.currentNumber+digit);
        this.props.changeMirror(this.props.mirror+digit);
        }
        break;
        
      case "dot":
        let dotregex = /[.]/;
        if(dotregex.test(this.props.currentNumber)) {
          break;
        }
        this.props.changeCurrentNumber(this.props.currentNumber+".");
        this.props.changeMirror(this.props.mirror+".");
        break;
        
      case "AC":
        this.props.clearDisplay();
        break;
        
      case "zero":
        if(this.props.currentNumber=="0") {
          this.props.changeMirror("0");
        }
        else if(this.props.currentNumber==".") {
          this.props.changeCurrentNumber("0."+"0");
          this.props.changeMirror("0."+"0");
        }
        
        else {
        this.props.changeCurrentNumber(this.props.currentNumber+"0");
        this.props.changeMirror(this.props.mirror+"0");
        }
        break;
        
      case "operator":
        if(event.target.value=="x") {
          this.props.changeMemory(this.props.memory+this.props.mirror+"*")
        }
        else {
          this.props.changeMemory(this.props.memory+this.props.mirror+event.target.value)
        }
        this.props.changeMirror("");
        this.props.changeCurrentNumber("0");
        break;
        
      case "equals":
        let complete = this.props.memory+this.props.mirror;
        let result = eval(complete);
        this.props.changeCurrentNumber(result);
        this.props.changeMirror(this.props.mirror+"="+result);
        this.props.changeCalcState("solved");
        break;
        
      default:
        console.log("nope");
    }
  }

在应该在该语句中执行的所有不同调度中,出于某种原因,似乎只执行了this.props.changeCalcState("normal"),我无法解释为什么会发生这种情况。在 if 语句的末尾添加“return”语句将导致所需的结果,但在这种情况下,需要单击 2 次,这不是我希望的行为。

这对我来说真的很令人费解,因为this.props.changeCalcState("normal")调度无论是否存在“return”语句都有效,而其他的则没有,所以我希望有人能解释为什么会发生这种情况以及发生了什么我可以在没有返回语句的情况下使 if 语句中的所有调度都触发。

代码:

JS:

let buttons = [
  {
    class: "AC",
    label: "AC",
    id: "btn_AC"
  },
  {
    class: "operator",
    label: "/",
    id: "btn_divide"
  },
  {
    class: "operator",
    label: "x",
    id: "btn_x"
  },
  {
    class: "digit",
    label: "7",
    id: "btn_7"
  },
  {
    class: "digit",
    label: "8",
    id: "btn_8"
  },
  {
    class: "digit",
    label: "9",
    id: "btn_9"
  },
  {
    class: "operator",
    label: "-",
    id: "btn_minus"
  },
  {
    class: "digit",
    label: "4",
    id: "btn_4"
  },
  {
    class: "digit",
    label: "5",
    id: "btn_5"
  },
  {
    class: "digit",
    label: "6",
    id: "btn_6"
  },
  {
    class: "operator",
    label: "+",
    id: "btn_plus"
  },
  {
    class: "digit",
    label: "1",
    id: "btn_1"
  },
  {
    class: "digit",
    label: "2",
    id: "btn_2"
  },
  {
    class: "digit",
    label: "3",
    id: "btn_3"
  },
  {
    class: "equals",
    label: "=",
    id: "btn_equals"
  },
  {
    class: "zero",
    label: "0",
    id: "btn_0"
  },
  {
    class: "dot",
    label: ".",
    id: "btn_dot"
  },
]

//--------------------------------------------------------------------------------------
//action type constants
const CHANGE_MEMORY = "CHANGE_MEMORY";
const CHANGE_CURRENTNUMBER = "CHANGE_CURRENTNUMBER";
const CLEAR_DISPLAY = "CLEAR_DISPLAY";
const CHANGE_MIRROR = "CHANGE_MIRROR";
const CHANGE_CALCSTATE = "CHANGE_CALCSTATE";

//Action creators
const AC_change_memory = function(memory) {
  return {type: CHANGE_MEMORY, memory: memory}
}
const AC_change_currentNumber = function(currentNumber) {
  return {type: CHANGE_CURRENTNUMBER, currentNumber: currentNumber};
}
const AC_clear_display = function() {
  return {type: CLEAR_DISPLAY};
}
const AC_change_mirror = function(mirror) {
  return {type: CHANGE_MIRROR, mirror: mirror};
}
const AC_change_calcState = function(calcState) {
  return {type: CHANGE_CALCSTATE, calcState: calcState};
}

//Mapping state and dispatch
const mapStateToProps = function(state) {
  return {memory: state.memory, currentNumber: state.currentNumber, mirror: state.mirror, calcState: state.calcState};
}
const mapDispatchToProps = function(dispatch) {
  return {changeMemory: function(memory) {
    dispatch(AC_change_memory(memory));
  },
          changeCurrentNumber: function(currentNumber) {
            dispatch(AC_change_currentNumber(currentNumber));
          },
          clearDisplay: function() {
            dispatch(AC_clear_display());
          },
          changeMirror: function(mirror) {
            dispatch(AC_change_mirror(mirror));
          },
          changeCalcState: function(calcState) {
            dispatch(AC_change_calcState(calcState));
          },
         };
}

//default state and reducer
const defaultState = {memory: "", currentNumber: "0", mirror: "", calcState: "normal"}
const rootReducer = function(state=defaultState, action) {
  switch(action.type) {
    case CHANGE_CALCSTATE:
      return Object.assign({}, state, {calcState: action.calcState});
      break;
    case CHANGE_MIRROR:
      return Object.assign({}, state, {mirror: action.mirror});
      break;
    case CLEAR_DISPLAY:
      return Object.assign({}, state, {memory: "", mirror: "", currentNumber: "0"});
      break;
    case CHANGE_CURRENTNUMBER:
      return Object.assign({}, state, {currentNumber: action.currentNumber});
      break;
    case CHANGE_MEMORY:
      return Object.assign({}, state, {memory: action.memory});
      break;
    default:
      return state;
  }
}


// R E A C T

class CalcButton extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  
  //function that handles click of all calculator buttons based on class
    handleClick(event) {
      
      if(this.props.calcState=="solved") {
        this.props.changeMemory(this.props.currentNumber)
        this.props.changeCurrentNumber("0");
        this.props.changeMirror("");
        this.props.changeCalcState("normal");
      }
      
    switch(event.target.className) {
      case "digit":
        let digit = event.target.value;
        if(this.props.currentNumber=="0") {
          this.props.changeCurrentNumber(digit);
          this.props.changeMirror(digit);
        }
        else if(this.props.currentNumber==".") {
          this.props.changeCurrentNumber("0."+digit);
          this.props.changeMirror("0."+digit);
        }
        else {
        this.props.changeCurrentNumber(this.props.currentNumber+digit);
        this.props.changeMirror(this.props.mirror+digit);
        }
        break;
        
      case "dot":
        let dotregex = /[.]/;
        if(dotregex.test(this.props.currentNumber)) {
          break;
        }
        this.props.changeCurrentNumber(this.props.currentNumber+".");
        this.props.changeMirror(this.props.mirror+".");
        break;
        
      case "AC":
        this.props.clearDisplay();
        break;
        
      case "zero":
        if(this.props.currentNumber=="0") {
          this.props.changeMirror("0");
        }
        else if(this.props.currentNumber==".") {
          this.props.changeCurrentNumber("0."+"0");
          this.props.changeMirror("0."+"0");
        }
        
        else {
        this.props.changeCurrentNumber(this.props.currentNumber+"0");
        this.props.changeMirror(this.props.mirror+"0");
        }
        break;
        
      case "operator":
        if(event.target.value=="x") {
          this.props.changeMemory(this.props.memory+this.props.mirror+"*")
        }
        else {
          this.props.changeMemory(this.props.memory+this.props.mirror+event.target.value)
        }
        this.props.changeMirror("");
        this.props.changeCurrentNumber("0");
        break;
        
      case "equals":
        let complete = this.props.memory+this.props.mirror;
        let result = eval(complete);
        this.props.changeCurrentNumber(result);
        this.props.changeMirror(this.props.mirror+"="+result);
        this.props.changeCalcState("solved");
        break;
        
      default:
        console.log("nope");
    }
  }
  
  render() {
    return (
        <button value={this.props.label} className = {this.props.class} id={this.props.id} onClick={()=>this.handleClick(event)}>{this.props.label}</button>
    )
  }
}

class ButtonBank extends React.Component {
  constructor(props) {
    super(props);
  }
  
  render() {
    let buttonbank = buttons.map(e=> {
      return <CalcButton {...this.props} id={e.id} label={e.label} class={e.class} />
    })
    return (<div id="calc_grid">{buttonbank}</div>)
  }
}

class Presentational extends React.Component {
  constructor(props) {
    super(props);

  }
  

  // anchor
  render() {
    return (
      <div id="container">
        <div id="calc_head">
          <div id="calc_display_top">{this.props.memory}{this.props.mirror}</div>
          <div id="calc_display_bottom">{this.props.currentNumber}</div>
        </div>
        <ButtonBank {...this.props} />
        <div>{this.props.calcState}</div>
      </div>
    )
  }
}


//-----------------------------------------------------------------------------------



const store = Redux.createStore(rootReducer, Redux.applyMiddleware(ReduxThunk.default));
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);

class AppWrapper extends React.Component {
  render() {
    return (<Provider store={store}>
      <Container />
    </Provider>)
  }
}

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

CSS:

#container {
  width: 30%;
  margin: auto;
}
#calc_grid {
  background-color: red;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(5, 1fr);
}
#btn_AC {
  grid-column: 1 / 3;
}
#btn_0 {
  grid-column: 1 / 3;
}
#btn_equals {
  grid-row: 4 / 6;
  grid-column: 4 / 5;
}

HTML:

<head>
</head>
<body>
  <div id="app">
  </div>
</body>

标签: javascriptreactjsreduxreact-redux

解决方案


推荐阅读