在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
预先感谢您的帮助。
答案 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
})
}