我对反应并不熟悉,我尝试在登录/表格等方面构建以下抽象。
看看这个:
var SignUpForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
console.log(this.refs.iitu_id.getDOMNode().value.trim())
// iitu_id = this.refs.iitu_id.getDOMNode().value.trim();
// password = this.refs.password.getDOMNode().value.trim();
var error = UserValidator.valid({iitu_id: iitu_id, password: password});
if (error) {
this.setState({"errors": error });
// console.log(error);
} else {
// console.log(error);
}
},
getInitialState: function() {
return {
'errors': {
iitu_id: null,
password: null
}
};
},
render: function() {
return (
/*jshint ignore:start */
<form className="form-horizontal" onSubmit={this.handleSubmit} >
<FormGroup label="iitu id" error_msg={this.state.errors.iitu_id} fieldName="iitu_id" fieldType="text" />
<FormGroup label="password" error_msg={this.state.errors.password} fieldName="password" fieldType="password" />
<ButtonGroup text="Войти"/>
</form>
/*jshint ignore:end */
);
}
});
var FormGroup = React.createClass({
render: function() {
var formGroupCss = 'form-group';
if (this.props.error_msg){
formGroupCss = 'form-group has-error';
}
return (
/*jshint ignore:start */
<div className={formGroupCss}>
<Label fieldName={this.props.fieldName}>{this.props.label}</Label>
<InputField type={this.props.fieldType}>{this.props.label}</InputField>
<label className="control-label" for="inputError1">{this.props.error_msg}</label>
</div>
/*jshint ignore:end */
);
}
});
var ButtonGroup = React.createClass({
render: function () {
return (
/*jshint ignore:start */
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button className="btn btn-default">{this.props.text}</button>
</div>
</div>
/*jshint ignore:end */
);
}
});
var InputField = React.createClass({
render: function() {
return (
/*jshint ignore:start */
<div className="col-sm-5">
<input className="form-control" type={this.props.fieldType} placeholder={this.props.children}/>
</div>
/*jshint ignore:end */
);
}
});
exports.SignUpForm = SignUpForm;
代码有点太多,但我觉得它很容易阅读。问题是当我按下提交按钮时(如果获取表单值),如何获取InputField类的值?我的输入标签存在于DOM内部的问题。另外一个问题是,拥有以下代码设计是否合适?我的意思是将每个逻辑组件描述为新的“类”?
答案 0 :(得分:7)
如果您提供表单输入name
属性,则可以使用表单.elements
集合来访问其输入。
我最近将用于此目的的代码newforms拆分为可重复使用的get-form-data模块,假设您的输入具有name
属性,则可以执行此操作:
var getFormData = require('get-form-data'); // Or just use the browser bundle
var SignUpForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var data = getFormData(e.target, {trim: true});
var error = UserValidator.valid(data);
if (error) {
this.setState({errors: error});
} else {
// ...
}
},
// ...
或者,如果您需要获得输入,可以向onChange
或包含所有表单输入的其他组件添加<form>
处理程序,而不是分别做每一个:
handleChange: function(e) {
var form = e.target.form;
var name = e.target.name;
var data = getFormData.getNamedFormElementData(form, name, {trim: true});
// ...
},
render: function() {
return <form onSubmit={this.handleSubmit} onChange={this.handleChange}>
{/* ... */}
</form>
}
});
答案 1 :(得分:2)
如果没有像Angular或Flux这样的框架,请使用回调在组件之间拍摄数据。
此处使用的技术是React网站上的explained in detail。然而,另一种解决方案是使用表单库。我采取了类似的路线,并尝试从头开始构建表单组件 - 它可以工作,但它是其他人已经清除的路径。查看newforms和react-forms。
请注意,我共享的代码未经测试,但它应该非常接近工作。
var SignUpForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
console.log(this.iitu_id + ' and ' + this.password + ' should work.');
var error = UserValidator.valid({iitu_id: iitu_id, password: password});
if (error) {
this.setState({"errors": error });
// console.log(error);
} else {
// console.log(error);
}
},
getInitialState: function() {
return {
'errors': {
iitu_id: null,
password: null
}
};
},
updateForm: function(field, value) {
/* Or do something like this using underscore.js:
var form = _.clone(this.form);
form[field] = value;
this.setState({ form: form });
This approach let's you grab the form object on
submit instead of hunting for the form values
in SignUpForm's state.
*/
this.setState({ field: value });
},
render: function() {
return (
/*jshint ignore:start */
<form className="form-horizontal" onSubmit={this.handleSubmit} >
<FormGroup update={this.updateForm} label="iitu id" error_msg={this.state.errors.iitu_id} fieldName="iitu_id" fieldType="text" />
<FormGroup label="password" error_msg={this.state.errors.password} fieldName="password" fieldType="password" />
<ButtonGroup text="Войти"/>
</form>
/*jshint ignore:end */
);
}
});
var FormGroup = React.createClass({
handleChange: function(event) {
this.props.update(this.props.fieldName, event.target.value);
},
render: function() {
var formGroupCss = 'form-group';
if (this.props.error_msg){
formGroupCss = 'form-group has-error';
}
return (
/*jshint ignore:start */
<div className={formGroupCss}>
<Label fieldName={this.props.fieldName}>{this.props.label}</Label>
<InputField handleChange={this.handleChange} type={this.props.fieldType}>{this.props.label}</InputField>
<label className="control-label" for="inputError1">{this.props.error_msg}</label>
</div>
/*jshint ignore:end */
);
}
});
var ButtonGroup = React.createClass({
render: function () {
return (
/*jshint ignore:start */
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button className="btn btn-default">{this.props.text}</button>
</div>
</div>
/*jshint ignore:end */
);
}
});
var InputField = React.createClass({
render: function() {
return (
/*jshint ignore:start */
<div className="col-sm-5">
<input onChange={this.props.handleChange} className="form-control" type={this.props.fieldType} placeholder={this.props.children}/>
</div>
/*jshint ignore:end */
);
}
});
exports.SignUpForm = SignUpForm;
具体来说,请注意从父级传递给子级的回调函数。
updateForm
提供给FormGroup handleChange
提供给InputField 然后,要将数据恢复到顶部,您只需撤消该过程。
<input/>
更改时,它会运行handleChange
handleChange
运行时,它会将FormGroup的fieldName
和value
传递给SignUpForm 答案 2 :(得分:1)
关于你的第二个问题 - 为每个逻辑元素添加一个组件是一个糟糕的方法。 在您的示例中 - 所有组件(除第一个之外)都没有逻辑,只有'render'。这种设计增加了许多无用的代码行和“this.props”重复。 在您的示例中,我只需将所有内容添加到第一个组件的渲染中。
现在,假设你有两个组件,并希望从父母那里联系到孩子:
var SignUpForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
//now - reach your inner comp with refs
console.log(this.refs.inner.refs.username.getDOMNode().value.trim());
},
render: function() {
return (
//and pass the submit function as a callback
<InnerForm ref="inner" submit={this.props.handleSubmit}/>
);
}
});
var InnerForm = React.createClass({
render: function() {
return (
<form>
<input type="text" ref="username"/>
<input type="submit" onClick={this.props.submit} >
</form>
);
}
});
在您的示例中,组件内部有许多组件可以执行我所做的操作。 但是,有些情况下需要长时间使用子组件。使用this.refs.a.refs.b.refs.c等 - 可能非常难看,并且还会阻止可重用性。
在这些情况下尝试使用任何MVC架构(我正在使用reflux并喜欢它)
答案 3 :(得分:1)
我建议您输入一个onChange
事件监听器,它使用回调将信息一直传递回您的顶级组件。
var SignUpForm = React.createClass({
getInitialState: function() {
return {
inputs: {
id: '',
password: ''
}
};
},
render: function() {
return (
<form className="form-horizontal" onSubmit={this.handleSubmit} >
<FormGroup ... callback={this.handleIdChange} />
<FormGroup ... callback={this.handlePasswordChange} />
<ButtonGroup text="Войти"/>
</form>
);
},
handleIdChange: function(newId) {
this.setState({
inputs: {
id: newId.target.value,
password: this.state.inputs.password
}
});
},
handlePasswordChange: function(newPassword) { ... }
});
然后将该回调传递给基础级别表单字段,并使用它们来处理onChange
事件。
var InputField = React.createClass({
render: function() {
return (
/*jshint ignore:start */
<div className="col-sm-5">
<input ... onChange={this.props.callback}/>
</div>
/*jshint ignore:end */
);
}
});
然后使用handleSubmit
输出this.state.inputs
对象中的值。