javascript - react : Why doesn't the state of my app become updated?

标签 javascript reactjs

我用 React JS 制作了这个小应用程序:

var TextBox = React.createClass({
  notify: function() {
    let item = this.refs.inputElement;
    
    this.props.changeHandler(item.dataset.variable, item);
  },
  render: function() {   
    return (
      <div className={ this.props.divClass }
           ref={ this.props.ref }>
          <input type="text"
                 placeholder={ this.props.placeholder} 
                 ref="inputElement" 
                 className={ this.props.textBoxClass }
                 disabled={ this.props.disabled } 
                 onChange={ this.notify }
                 data-variable={ this.props.variable } />
      </div>
    );
  }
});

var Button = React.createClass({
  render: function() {
    function notify(e) {
      this.props.handler(e.target.dataset.operation);
    }
    
    return (
      <div className={ this.props.classDiv }>
        <a href='#' className={ this.props.classButton } 
                    onClick={ notify.bind(this) }
                    data-operation={ this.props.operation }>
          { this.props.value }
        </a>
      </div>
    );
  }
});

var Calculator = React.createClass({
  INIT_STATE: { a: 'Enter a number ! For example 248',
                b: 'Enter a number ! For example 1632',
                aClass: 'input-box',
                bClass: 'input-box' },
  operations: {
    'add': function() {
      return this.state.a + this.state.b;
    },
    'subtract': function() {
      return this.state.a - this.state.b;
    },
    'multiply': function() {
      return this.state.a * this.state.b;
    },
    'divide': function() {
      return this.state.a / this.state.b;
    }
  },
  getInitialState: function() {
    return this.INIT_STATE; 
  },
  updateNumbers: function(variable, reference) { 
    var val = parseFloat(reference.value);
    var varClass = [variable + 'Class'];
    
    if (typeof val === 'number' && !isNaN(val)) {
      if (this.state[variable + 'Class'].indexOf('invalid-input') > -1) {
        this.setState({
          [varClass]: this.state[varClass].split(' ')[0]
        })
      }
      
      this.setState({
        [variable]: val
      });
    } else {
      this.setState({
        [varClass]: [varClass] + ' invalid-input'
      });
    }
  },
  triggerOperation: function(operation) {
    var result = this.operations[operation].call(this);
    
    this.refs.resultBox.refs.inputElement.value = result;
  },
  resetForm: function() {
    this.setState(this.INIT_STATE);
    this.forceUpdate();
    console.log(this.state);
  },
  render: function() {
    var that = this;
    
    var navButtons = this.props.navButtons.map(function(button) {
      return (
        <div>
          <Button value={ button.value } classDiv={ button.classDiv }
                  classButton={ button.classButton }
                  handler={ that.triggerOperation } operation={ button.operation }/>
        </div>
      );
    });
    
    return (
      <div className="calculator">
        
        <div className="row">
          <h1>Simple calculator</h1>
        </div>
        
        <div className="row">
          <TextBox divClass="large-6 columns"
                   placeholder={ this.state.a }
                   ref="a" textBoxClass={ this.state.aClass }
                   value={ this.state.a }
                   changeHandler={ this.updateNumbers }
                   variable="a"
                   />
          <TextBox divClass="large-6 columns"
                   placeholder={ this.state.b }
                   ref="b" textBoxClass={ this.state.bClass }
                   value={ this.state.b }
                   changeHandler={ this.updateNumbers }
                   variable="b"
                   />
        </div>
        
        <div className="row">
          { navButtons }
        </div>
        
        <div className="row">
          <TextBox divClass="large-9 columns"
                   placeholder="Result"
                   ref="resultBox" textBoxClass="input-box"
                   disabled="disabled" />
          <Button value="Clear" classDiv="large-3 columns"
                  classButton="attention nav-button"
                  handler={ this.resetForm } />
        </div>     
      </div>
    );
  }
});

var NAV_BUTTONS = [
  { classDiv: 'large-3 column',
    value: '+ Add',
    classButton: 'calculation-method nav-button',
    operation: 'add'
  },
  { classDiv: 'large-3 column',
    value: '- Subtract',
    classButton: 'calculation-method nav-button',
    operation: 'subtract'
  },
  { classDiv: 'large-3 column',
    value: 'x Multiply',
    classButton: 'calculation-method nav-button',
    operation: 'multiply'
  },
  { classDiv: 'large-3 column',
    value: '/ Divide',
    classButton: 'calculation-method nav-button',
    operation: 'divide'
  }
];

ReactDOM.render(<Calculator navButtons={ NAV_BUTTONS } />, document.getElementById('app'));
$primaryColor: rgba(245, 245, 245, 1.0);
$secondaryColor: rgba(150, 150, 150, 1.0);
$lightUp: 20%;
$buttonColor: rgba(51, 71, 255, 1.0);
$borderRadius: 6px;

@mixin addPseudoClasses($selector, $color) {
  #{$selector}:visited, #{$selector}:hover {
    color: white;
  }

  #{$selector}:hover {
    background: linear-gradient(lighten($color, $lightUp), $color); 
    color: white;
  }

    #{$selector}:active {
    opacity: 0.6;
  }
}

body {
  background: linear-gradient(lighten($secondaryColor, $lightUp), $secondaryColor);
}

.nav-button {
  text-decoration: none;
  color: white;
  padding: 5px 20px;
  background-color: powderBlue;
  text-align: center;
  font-weight: 900;
  margin-bottom: 16px;
  display: inline-block;
  width: 100%;
  border-radius: $borderRadius;
}

.calculation-method { 
  background: linear-gradient(lighten($buttonColor, $lightUp), $buttonColor); 
}

@include addPseudoClasses('.calculation-method', orangered);

h1 {
  text-align: center;
  margin: 20px 0 30px;
}

.attention {
  background: linear-gradient(darken(deepPink, 20%), lighten(deepPink, 20%));
  text-transform: uppercase;
}

@include addPseudoClasses('.attention', red);

.invalid-input {
  border-color: red !important;
  background-color: pink !important;
}
<div class="wrap">
  <div id="app"></div>
</div>

工作现场演示: http://codepen.io/mizech/pen/VKvNKX

到目前为止,一切都很顺利。但现在我想实现清晰形式的功能,但遇到了问题。

当单击“CLEAR”按钮时,我(尝试)使用 this.setState() 将状态设置为初始值。

假设我在第一个文本框中输入了 5,在第二个文本框中输入了 4。然后我单击“添加”来计算总和。

然后我单击“清除”以重置表单。执行“resetForm”方法。

我希望国家成为:

[object Object]{a: '输入一个数字!例如248', aClass: "input-box", b: '输入一个数字!例如1632',bClass:“输入框”}

相反,它保留:

[object Object]{a: 5, aClass: "input-box", b: 4, bClass: "input-box"}

到目前为止我的“forceUpdate”之后没有效果。

使用对象文字( this.setState({ a: 'Enter number' }); )也不起作用:

如果我改变状态,接收状态作为 props 的元素也应该改变。但他们不...

我在这里做错了什么? 如何将表单重置为其初始值?而不重新加载。

最佳答案

TextBox 组件正在接收 prop value 但您没有使用它,这就是它不重新渲染的原因。

您的Textbox组件应该是

var TextBox = React.createClass({
  notify: function() {
    let item = this.refs.inputElement;

    this.props.changeHandler(item.dataset.variable, item);
  },
  render: function() {   
    return (
      <div className={ this.props.divClass }
           ref={ this.props.ref }>
          <input type="text"
                 placeholder={ this.props.placeholder} 
                 ref="inputElement" 
                 className={ this.props.textBoxClass }
                 disabled={ this.props.disabled } 
                 onChange={ this.notify }
                 data-variable={ this.props.variable } 
                 value={this.props.value} // You were missing this
            />
      </div>
    );
  }
});

和你的resetForm()方法

resetForm: function() {
    this.setState(this.INIT_STATE, () => console.log(this.state));
},

fixed codepen

片段

var TextBox = React.createClass({
  notify: function() {
    let item = this.refs.inputElement;
    
    this.props.changeHandler(item.dataset.variable, item);
  },
  render: function() {   
    return (
      <div className={ this.props.divClass }
           ref={ this.props.ref }>
          <input type="text"
                 placeholder={ this.props.placeholder} 
                 ref="inputElement" 
                 className={ this.props.textBoxClass }
                 disabled={ this.props.disabled } 
                 onChange={ this.notify }
                 data-variable={ this.props.variable } 
                 value={this.props.value}
            />
      </div>
    );
  }
});

var Button = React.createClass({
  render: function() {
    function notify(e) {
      this.props.handler(e.target.dataset.operation);
    }
    
    return (
      <div className={ this.props.classDiv }>
        <a href='#' className={ this.props.classButton } 
                    onClick={ notify.bind(this) }
                    data-operation={ this.props.operation }>
          { this.props.value }
        </a>
      </div>
    );
  }
});

var Calculator = React.createClass({
  INIT_STATE: { a: 'Enter a number ! For example 248',
                b: 'Enter a number ! For example 1632',
                aClass: 'input-box',
                bClass: 'input-box' },
  operations: {
    'add': function() {
      return this.state.a + this.state.b;
    },
    'subtract': function() {
      return this.state.a - this.state.b;
    },
    'multiply': function() {
      return this.state.a * this.state.b;
    },
    'divide': function() {
      return this.state.a / this.state.b;
    }
  },
  getInitialState: function() {
    return this.INIT_STATE; 
  },
  updateNumbers: function(variable, reference) { 
    var val = parseFloat(reference.value);
    var varClass = [variable + 'Class'];
    
    if (typeof val === 'number' && !isNaN(val)) {
      if (this.state[variable + 'Class'].indexOf('invalid-input') > -1) {
        this.setState({
          [varClass]: this.state[varClass].split(' ')[0]
        })
      }
      
      this.setState({
        [variable]: val
      });
    } else {
      this.setState({
        [varClass]: [varClass] + ' invalid-input'
      });
    }
  },
  triggerOperation: function(operation) {
    var result = this.operations[operation].call(this);
    
    this.refs.resultBox.refs.inputElement.value = result;
  },
  resetForm: function() {
    this.setState(this.INIT_STATE);
  },
  render: function() {
    var that = this;
    
    var navButtons = this.props.navButtons.map(function(button) {
      return (
        <div>
          <Button value={ button.value } classDiv={ button.classDiv }
                  classButton={ button.classButton }
                  handler={ that.triggerOperation } operation={ button.operation }/>
        </div>
      );
    });
    
    return (
      <div className="calculator">
        
        <div className="row">
          <h1>Simple calculator</h1>
        </div>
        
        <div className="row">
          <TextBox divClass="large-6 columns"
                   placeholder={ this.state.a }
                   ref="a" textBoxClass={ this.state.aClass }
                   value={ this.state.a }
                   changeHandler={ this.updateNumbers }
                   variable="a"
                   value={this.state.a}
                   />
          <TextBox divClass="large-6 columns"
                   placeholder={ this.state.b }
                   ref="b" textBoxClass={ this.state.bClass }
                   value={ this.state.b }
                   changeHandler={ this.updateNumbers }
                   variable="b"
                   value={this.state.b}
                   />
        </div>
        
        <div className="row">
          { navButtons }
        </div>
        
        <div className="row">
          <TextBox divClass="large-9 columns"
                   placeholder="Result"
                   ref="resultBox" textBoxClass="input-box"
                   disabled="disabled" />
          <Button value="Clear" classDiv="large-3 columns"
                  classButton="attention nav-button"
                  handler={ this.resetForm } />
        </div>     
      </div>
    );
  }
});

var NAV_BUTTONS = [
  { classDiv: 'large-3 column',
    value: '+ Add',
    classButton: 'calculation-method nav-button',
    operation: 'add'
  },
  { classDiv: 'large-3 column',
    value: '- Subtract',
    classButton: 'calculation-method nav-button',
    operation: 'subtract'
  },
  { classDiv: 'large-3 column',
    value: 'x Multiply',
    classButton: 'calculation-method nav-button',
    operation: 'multiply'
  },
  { classDiv: 'large-3 column',
    value: '/ Divide',
    classButton: 'calculation-method nav-button',
    operation: 'divide'
  }
];

ReactDOM.render(<Calculator navButtons={ NAV_BUTTONS } />, document.getElementById('app'));
body {
  background: linear-gradient(#c9c9c9, #969696);
}

.nav-button {
  text-decoration: none;
  color: white;
  padding: 5px 20px;
  background-color: powderBlue;
  text-align: center;
  font-weight: 900;
  margin-bottom: 16px;
  display: inline-block;
  width: 100%;
  border-radius: 6px;
}

.calculation-method {
  background: linear-gradient(#99a3ff, #3347ff);
}

.calculation-method:visited, .calculation-method:hover {
  color: white;
}

.calculation-method:hover {
  background: linear-gradient(#ff8f66, orangered);
  color: white;
}

.calculation-method:active {
  opacity: 0.6;
}

h1 {
  text-align: center;
  margin: 20px 0 30px;
}

.attention {
  background: linear-gradient(#ad005d, #ff7ac2);
  text-transform: uppercase;
}

.attention:visited, .attention:hover {
  color: white;
}

.attention:hover {
  background: linear-gradient(#ff6666, red);
  color: white;
}

.attention:active {
  opacity: 0.6;
}

.invalid-input {
  border-color: red !important;
  background-color: pink !important;
}
<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 class="wrap">
  <div id="app"></div>
</div>

fixed codepen

关于javascript - react : Why doesn't the state of my app become updated?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39449255/

相关文章:

javascript - 使用 Measurement Protocol 时 Google Analytics 屏幕时间不正确

javascript - 如何在后端以自动方式录制 HTML 动画并将其保存为视频

javascript - 更改页面加载后动态添加的元素的 onclick 处理程序

javascript - 在 Vue.js 中生成动态 img 路径

reactjs - TypeScript 2.6 -> Material-ui 1.0.0-beta.24 withStyles with React-router withRouter -> 类型中缺少属性 'classes'

javascript - 如何使用 jQuery 在列表中选择正确的按钮?

javascript - ReactJS 和继承

javascript - Netlify 表单不适用于 Material-UI 模式

javascript - 无法读取未定义的属性 'props' - React Router

javascript - 使用 React Hooks 输入千位分隔符