[英]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>
);
}
});
但是這樣,我會遇到兩個錯誤:
我無法在Form中找到Input的props.name,因為InputEmail中沒有。
在Input的呈現函數中,狀態為null
如何創建可重用/繼承的組件? 我無法同時使用合成模式和mixins
我添加了完整的代碼:表格
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')
);
PS:我試圖在jsfiddle上添加此代碼,但得到“!TypeError:無法定義屬性“ attachToForm”:對象不可擴展”
設置有兩個主要問題:
<Form>
是以這樣的方式設置的,即該表單的子級需要有道具,否則它將不起作用。 <InputEmail>
包裝器不完整。 它需要將所有道具傳遞到<Input>
,包括向下傳遞的Form函數。 廣告1:修正表格,以確保添加了驗證方法
出現錯誤的原因是<Form>
子代需要具有props.name。 然后,通過將窗體的功能(包括attachToForm)添加到子級中來注冊它們。 這是在方法registerInputs()
。
在原始變體中, <Input>
組件具有道具,因此一切順利。
在改編的變體中,包裝器<InputEmail>
不再具有道具,因此, attachToForm()
和其他函數不會添加到道具,並且當<Input>
嘗試調用該函數時會出現錯誤。
解決此問題的最簡單方法:在render函數中添加至少1個prop,然后在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
。
作為次要問題,我建議再進行2處更改:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.