React-Bootstrap 带有表单字段验证的弹出窗口

React-Bootstrap Popover with Form field Validation

我试图利用显示的示例代码 here 来获得一个覆盖触发器,该触发器在我的表单组件的用户名字段正则表达式无效时显示弹出窗口。我在尝试执行此代码时遇到经典的 Cannot update during an existing state transition (such as within "render"). Render methods should be a pure function of props and state. 错误:

var UserField = React.createClass({
  getInitialState: function() {
    return {
      value: ''
    };
  },

  getValue: function() {
    return this.refs.input.getValue();
  },

  validationState: function() {
    let valueCode = this.state.value;
    if (valueCode.length > 0) {
      switch (valueCode.match(/^[A-Za-z0-9_-]+$/)) {
        case null:
          this.refs.userHint.show();
          return 'warning';
          break;

        default:
          this.refs.userHint.hide();
          return '';
          break;
      }
    }
  },

  handleChange: function() {
    this.setState({
      value: this.refs.input.getValue()
    });
  },

  render: function() {
    return (
      <OverlayTrigger
        ref="userHint"
        trigger="manual"
        placement="right"
        overlay={<Popover title='Invalid Username Format'>
                   <strong>Warning!</strong> Valid user credentials only contain alphanumeric characters, as well as heifens and underscores.
                 </Popover>
        }
      >
        <Input
          type = 'text'
          value = {this.state.value}
          label = 'Username'
          bsStyle = {this.validationState()}
          ref = 'input'
          groupClassName = 'input-group'
          className = 'form-control'
          onChange = {this.handleChange}
        />
      </OverlayTrigger>
    );
  }
});

一如既往,非常感谢您对此提供的任何帮助。谢谢。

如果我正在开发这个,我会做不同的事情,Input 管理它自己的验证并通过它的状态公开它是否有效(可通过 refs 访问)。

在不改变您的方法的情况下,这应该会更好地工作,因为它不会触发父组件状态的变化,直到显示或隐藏叠加层:

validationState: function() {
  let valueCode = this.state.value;
  if (valueCode.length > 0) {
    switch (valueCode.match(/^[A-Za-z0-9_-]+$/)) {
      case null:
        return 'warning';
        break;

      default:
        return '';
        break;
    }
  }
},

handleChange: function() {
  let valueCode = this.refs.input.getValue();

  if (valueCode.length > 0) {
    switch (valueCode.match(/^[A-Za-z0-9_-]+$/)) {
      case null:
        this.refs.userHint.show();
        break;

      default:
        this.refs.userHint.hide();
        break;
    }
  }
  this.setState({
    value: valueCode
  });
},