涉及受控选择组件的Reactjs表单提交不起作用

时间:2019-05-11 05:25:55

标签: reactjs

在React中,涉及受控选择组件的表单提交不起作用。

似乎React在实际的dom中没有正确设置'selected'属性。您可以在React自己的示例中看到这一点; https://codepen.io/gaearon/pen/JbbEzX?editors=0010从React文档中链接到select组件; https://reactjs.org/docs/forms.html#the-select-tag示例如下:

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

ReactDOM.render(
  <FlavorForm />,
  document.getElementById('root')
);

如果运行Codepen示例并检查Chrome开发人员工具中的选择菜单,则会看到最初没有选择任何选项。现在选择一个选项并再次检查。仍然没有选择任何选项!

在我自己的代码中,我有一个受控的选择菜单,用于选择月份。我有一个回调来处理表单的onSubmit。它首先调用preventDefault(),然后对表单进行验证,如果验证了,则调用event.currentTarget.submit()完成表单的提交。发生的事情是,验证成功(尤其是validateChildBirthDate()),因为状态正确,但是提交的表单在服务器上的验证失败,因为编码表单中的选择菜单没有选择。我的代码在下面,请记住,上面的代码是React文档。

这是我的“月”菜单的代码(我正在使用TypeScript)。请注意记录this.props.month;的console.log();它记录了预期的月份值,但在实际dom中从未为关联的option元素提供'selected'属性:

import React from 'react';
import "./DatePicker.scss";


export type MonthPickerProps = {
    name: string,       // 'menuId' attribute of select element
    month: number,                  // initially selected month
    onMonthChange(month: number): void   // callback when month changes
}

export default class MonthPicker extends React.Component<MonthPickerProps, {}, any> {

    onMonthChange = (event: React.FormEvent<HTMLSelectElement>): void => {
        const month = Number(event.currentTarget.value);
        if('function' === typeof this.props.onMonthChange) {
            this.props.onMonthChange(month);
        }
    };

    render () {
        console.log(`MonthPicker.render(): month = ${this.props.month}`);

        return (
            <select name={this.props.name}
                    value={this.props.month}
                    onChange={this.onMonthChange}
                    className="monthPickerContainer dateSelector">
                <option key="-1" value="-1">mm</option>
                <option key="0"  value="0" >Jan</option>
                <option key="1"  value="1" >Feb</option>
                <option key="2"  value="2" >Mar</option>
                <option key="3"  value="3" >Apr</option>
                <option key="4"  value="4" >May</option>
                <option key="5"  value="5" >Jun</option>
                <option key="6"  value="6" >Jul</option>
                <option key="7"  value="7" >Aug</option>
                <option key="8"  value="8" >Sep</option>
                <option key="9"  value="9" >Oct</option>
                <option key="10" value="10">Nov</option>
                <option key="11" value="11">Dec</option>
            </select>
        );
    }
}

这是我来自有状态父级组件的代码,用于处理表单组件的onSubmit。验证将通过,因此event.currentTarget.submit()将被调用,但是由于月份选择菜单的输入值始终为-1,因此服务器上的验证将失败。

onRegistrationSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault(); // prevent default so we can validate

    // 1. validate email, if error, show error
    // 2. validate password, if error then show errors
    // 3. validate precon/due date, if error, show error
    // 4. else if no errors, collect fields and submit
    let showErrors = false;
    this.setState({showErrors: false});


    // 1. validate email, if error, show error
    const emailState = validateEmailState(this.state.email.value);
    if(isNotBlank(emailState.errorMessage)) {
        showErrors = true;
        this.setState({showErrors: true, email: emailState});
    }

    // 2. validate password, if error then show errors
    const passwordState = validatePasswordState(this.state.password.value);
    if(isNotBlank(passwordState.errorMessage)) {
        showErrors = true;
        this.setState({showErrors: true, password: passwordState});
    }

    // 3. validate precon/due date, if error, show error
    if(!this.state.isPrecon) {
        const childBirthDateState = validateChildBirthDate(this.state.birthDate.value);
        if(isNotBlank(childBirthDateState.errorMessage)) {
            showErrors = true;
            this.setState({showErrors: true, birthDate: childBirthDateState});
        }
    }

    // 4. else if no errors, collect fields and submit
    if(!showErrors) {
        event.currentTarget.submit();

        console.log("Registration submitted");
    }
};

在select组件的实现中这是一个已知问题吗?您知道任何变通办法吗?

我正在使用react and react-dom 16.7

预先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

React的工作方式与纯HTML表单元素略有不同,在纯HTML表单元素中,您将选定的值发布到服务器,以响应选择的内容由虚拟DOM处理,因此您将在组件中获得选定的值状态,当您提交表单时,handleSubmit方法将触发,您可以在其中使用状态值执行某些操作,例如调用API提交数据。

由于您使用的是event.preventDefault(),因此提交不会按应有的方式工作,因为您停止了该事件,然后您告诉了反应,所以让我按自己的方式进行处理。

handleSubmit (event) {
  event.preventDefault();

  const flavor = this.state.value;

  // validate the flavor here
  if (!flavor) return;

  // make a call to an API to do something with the data
  axios.post('/save', { data: flavor }).then({
    // do something else if the call succeeds
    // example: clear the state or show something in the UI like a success notice
  }).catch(e => {
    // or handle the error
    return e
  })
}