React JS:可重用组件
React JS: Reusable components
我已经用类似的结构创建了表单验证
var Signin = React.createClass({
render: function() {
return (
<Form>
<Input type="text" name="email" labelName="Email" rules="isEmail" error:"Email not valid" />
<Input type="password" name="password" labelName="Password" rules="isLength:6" error:"Passowrd not valid"/>
</Form>
);
}
});
例如,因为"电子邮件"输入将在应用程序的不同部分使用,我会避免每次添加相同的属性(名称、类型、labelName、规则和错误)。所以我会创建这样的
var InputEmail = React.createClass({
render: function () {
return (
<Input type="text" name="email" labelName="Email" rules="isEmail" error="Email not valid"/>
)
}
});
var InputPassword = React.createClass({
render: function () {
return (
<Input type="password" name="password" labelName="Password" rules="isLength:6" error="Passwordnot valid"/>
)
}
});
所以登录组件应该是
var Signin = React.createClass({
render: function() {
return (
<Form>
<InputEmail />
<InputPassword />
</Form>
);
}
});
但是这样,我得到了两个错误:
我在表单中找不到Input的props.name,因为InputEmail中没有;
在Input的呈现函数中,状态为空
如何创建可重用/继承的组件?我使用合成模式和混合都失败了
我添加了我的完整代码:Form
var Form = React.createClass({
getInitialState: function () {
return {
isValid : false,
isSubmitting: false
}
},
componentWillMount: function(){
this.model = {};
this.inputs = {};
this.registerInputs(this.props.children);
},
registerInputs: function(children){
React.Children.forEach(children, function (child) {
if (child.props.name) {
child.props.attachToForm = this.attachToForm;
child.props.detachFromForm = this.detachFromForm;
child.props.validate = this.validate;
}
if (child.props.children) {
this.registerInputs(child.props.children);
}
}.bind(this));
},
attachToForm: function (component) {
this.inputs[component.props.name] = component;
this.model[component.props.name] = component.state.value;
this.validate(component);
},
detachFromForm: function (component) {
delete this.inputs[component.props.name];
delete this.model[component.props.name];
},
validate: function (component) {
var isValid = true;
// validation code
component.setState({
isValid: isValid,
}, this.validateForm);
},
validateForm: function () {
var formIsValid = true;
var inputs = this.inputs;
Object.keys(inputs).forEach(function (name) {
if (!inputs[name].state.isValid) {
formIsValid = false;
}
});
this.setState({
isValid: formIsValid
});
},
updateModel: function (component) {
Object.keys(this.inputs).forEach(function (name) {
this.model[name] = this.inputs[name].state.value;
}.bind(this));
},
submit: function (event) {
event.preventDefault();
this.setState({
isSubmitting : true
});
this.updateModel();
console.log(this.model);
},
render: function () {
return (
<form className="ui form" onSubmit={this.submit}>
{this.props.children}
<button className="ui button" type="submit" disabled={this.state.isSubmitting}>Accedi</button>
</form>
);
}
});
输入
var Input = React.createClass({
getInitialState: function(){
return {
value : this.props.value || "",
isValid: true
}
},
setValue: function (event) {
this.setState({
value: event.target.value
}, function () {
this.props.validate(this);
}.bind(this));
},
componentWillMount: function () {
if (this.props.required) {
this.props.validations = this.props.validations ? this.props.validations + ',' : '';
this.props.validations += 'isLength:1';
}
// ERROR: TypeError: this.props.attachToForm is not a function
this.props.attachToForm(this);
},
componentWillUnmount: function () {
this.props.detachFromForm(this);
},
render: function () {
var className = "field";
if(this.props.className){
className += " " + this.props.className;
}
if(this.props.required){
className += " required";
}
var Label;
if(this.props.labelName){
Label = (<label htmlFor={this.props.name}>{this.props.labelName}</label>);
}
var Error;
if(!this.state.isValid){
Error = (<div className="ui">{this.props.error || this.props.name + " not valid"}</div>);
};
return (
<div className={className}>
{Label}
<input type={this.props.type || "text"} id={this.props.name} name={this.props.name} onChange={this.setValue} value={this.state.value} />
{Error}
</div>
);
}
});
有了这个作品
ReactDOM.render(
<Form>
<Input type="text" name="email" labelName="Email" rules="isEmail" error:"Email not valid"/>
</Form>,
document.getElementById('app')
);
通过这种方式,我得到:"TypeError:this.props.attachToForm不是函数this.props.attachToForm(this);"
ReactDOM.render(
<Form>
<InputEmail/>
</Form>,
document.getElementById('app')
);
p.S:我试图在jsfiddle上添加此代码,但我得到了"!TypeError:无法定义属性"attachToForm":对象不可扩展"
jsfiddle
您的设置有两个主要问题:
- 您的
<Form>
是以这样一种方式设置的,即表单的子级需要有道具,否则它将不起作用 <InputEmail>
包装不完整。它需要将所有道具传递给<Input>
,包括传递下来的Form函数
广告1:修复表单,以确保添加验证方法
出现错误的原因是<Form>
的子级需要有props.name。然后,它通过将函数添加到子级来注册表单的函数(包括attachToForm)。这是在方法registerInputs()
中完成的。
在最初的变体中,<Input>
组件有道具,所以一切都很顺利。
在适配的变体中,包装器<InputEmail>
不再具有props,因此attachToForm()
和其他函数不会添加到props中,并且当<Input>
尝试调用该函数时会出现错误。
最简单的方法是:在渲染函数中添加至少一个道具,并在registerInputs()
中检查,例如:
ReactDOM.render(
<Form>
<InputEmail initialValue={'name@domain.com'}/>
</Form>,
document.getElementById('app')
);
在registerInputs()
中,更改行:
if (child.props.name) {
至:
if (child.props.initialValue) {
2.扩展<InputEmail>
包装器以传递函数
最简单的方法是添加{...this.props}
,如下所示:
var InputEmail = React.createClass({
render: function () {
return (
<Input {...this.props}
type="text" name="email" labelName="Email" rules="isEmail" error="Email not valid"/>
)
}
});
这样,<Form>
传递给<InputEmail>
组件的函数(以及任何其他道具)将传递给<Input>
组件。
PS:registerInputs()
中检查child.props.children的代码没有按预期工作:在调用它时,<InputEmail>
组件没有子级。顾名思义,它检查作为道具流传下来的孩子。唯一通过的道具是initialValue
。
作为次要问题,我建议再做两个更改:
- 在
registerInputs()
中,您可以直接修改道具。这通常不是一个好主意。最好是制作一个道具副本,并将你的成型方法添加到副本中。您可以使用React.Children.map
来执行此操作。请参阅此处的官方文档 - 与其在
<InputEmail>
中对<Input>
组件的name="email"
等进行硬编码,不如使用propTypes
将这些组件的默认值放在道具的默认值中,如官方文档中所述
- 如何创建带有插槽的vue js组件预加载程序
- 如何在react js中将值从一个组件发送到另一个组件
- 如何在react js中移动第二个组件
- React js更改状态不会更新组件
- ember-js组件初始化不同的函数
- 复选框保持React JS中各组件的状态
- 如何在cycle js中从JSON数组创建组件
- Vue.js获取组件中的一个元素
- Ember.js(v2.4.5)组件不是't错过第二个动作
- 将自定义脚本加载到Vue.js组件中
- Ember.js:接受的子组件和父组件之间通信的最佳实践
- 使用react.js渲染其他组件内部的组件
- React.js不区分同一类的两个组件
- Ember.js:未在组件'中渲染的模型的计算属性;关于变更的参考
- 如何忽略node.js中其他文件或组件所需的文件
- React.js简单组件组成问题
- 在多个react.js组件中呈现json数据
- 以最封装的方式封装/封装ScalaJS react js组件(react stick)
- 需要来自单个JS文件的多个子模块与节点/组件.js
- 在组件.js内加载客户 sapui5 库