reactjs - 涉及受控选择组件的 Reactjs 表单提交不起作用
问题描述
在 React 中,涉及受控选择组件的表单提交不起作用。
似乎 React 没有正确设置实际 dom 中的 'selected' 属性。您可以在 React 自己的示例中看到这一点;https://codepen.io/gaearon/pen/JbbEzX?editors=0010从选择组件的 React 文档链接;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 中赋予“选择”属性:
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");
}
};
这是选择组件实现中的一个已知问题吗?您知道的任何解决方法?
我正在使用 react 和 react-dom 16.7
在此先感谢您的帮助。
解决方案
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
})
}
推荐阅读
- ios - 如果.srt文件包含多行字幕文本,如何在swift中使用Scanner解析它?
- java - Java验证日期是否在本周
- mysql - 错误 1290:secure_file_priv
- java - 两个整数都可以大于 Integer.MAX_VALUE 的数字吗?
- python - 创建 Numpy 数组或可变长度数组
- c++ - Qt:如何从另一个类调用主窗口的指针?
- angular - 属性在 Angular 中引发未定义的错误
- selenium - 在选中和未选中的情况下,如何验证 xpaths 是否相同的复选框
- git - 长路径的 git clone 命令问题
- laravel-5.6 - 如何在 Laravel 5.6 中设置 $error