Güncelleme: bu cevap güncel değil. Mümkünse karışımlardan uzak durun. Seni uyardım!
Mixins öldü. Yaşasın Kompozisyon
İlk başta, bu ve özü için alt bileşenlerini kullanmaya çalıştı FormWidgetve InputWidget. Ancak, bu yaklaşımı yarıda bıraktım çünkü üretilen inputlerin ve onların durumlarının daha iyi kontrol edilmesini istiyordum .
Bana en çok yardımcı olan iki makale:
Sadece iki (farklı) mix yazmam gerektiği ortaya çıktı: ValidationMixinve FormMixin.
İşte onları nasıl ayırdım.
ValidationMixin
Doğrulama karışımı, doğrulayıcı işlevlerinizi eyaletinizin özelliklerinden bazıları üzerinde çalıştırmak ve "hatalı" özellikleri bir state.errorsdizide depolamak için kolaylık yöntemleri ekler, böylece ilgili alanları vurgulayabilirsiniz.
Kaynak ( özet )
define(function () {
'use strict';
var _ = require('underscore');
var ValidationMixin = {
getInitialState: function () {
return {
errors: []
};
},
componentWillMount: function () {
this.assertValidatorsDefined();
},
assertValidatorsDefined: function () {
if (!this.validators) {
throw new Error('ValidatorMixin requires this.validators to be defined on the component.');
}
_.each(_.keys(this.validators), function (key) {
var validator = this.validators[key];
if (!_.has(this.state, key)) {
throw new Error('Key "' + key + '" is defined in this.validators but not present in initial state.');
}
if (!_.isFunction(validator)) {
throw new Error('Validator for key "' + key + '" is not a function.');
}
}, this);
},
hasError: function (key) {
return _.contains(this.state.errors, key);
},
resetError: function (key) {
this.setState({
'errors': _.without(this.state.errors, key)
});
},
validate: function () {
var errors = _.filter(_.keys(this.validators), function (key) {
var validator = this.validators[key],
value = this.state[key];
return !validator(value);
}, this);
this.setState({
'errors': errors
});
return _.isEmpty(errors);
}
};
return ValidationMixin;
});
kullanım
ValidationMixinüç yöntem vardır: validate, hasErrorve resetError.
Şuna validatorsbenzer şekilde sınıfın nesneyi tanımlamasını bekler propTypes:
var JoinWidget = React.createClass({
mixins: [React.addons.LinkedStateMixin, ValidationMixin, FormMixin],
validators: {
email: Misc.isValidEmail,
name: function (name) {
return name.length > 0;
}
},
// ...
});
Kullanıcı gönderme düğmesine bastığında ararım validate. Bir çağrı, validateher doğrulayıcıyı çalıştırır ve this.state.errorsdoğrulaması başarısız olan özelliklerin anahtarlarını içeren bir diziyle doldurulur .
Benim içinde renderyöntemle, kullandığım hasErroralanlar için doğru CSS sınıfı oluşturmak için. Kullanıcı alana odaklandığında, bir resetErrorsonraki validateçağrıya kadar hata vurgulamasını kaldırmak için çağrıda bulunuyorum.
renderInput: function (key, options) {
var classSet = {
'Form-control': true,
'Form-control--error': this.hasError(key)
};
return (
<input key={key}
type={options.type}
placeholder={options.placeholder}
className={React.addons.classSet(classSet)}
valueLink={this.linkState(key)}
onFocus={_.partial(this.resetError, key)} />
);
}
FormMixin
Form mixin, form durumunu işler (düzenlenebilir, gönderiliyor, gönderiliyor). Bunu, istek gönderilirken girişleri ve düğmeleri devre dışı bırakmak ve gönderildiğinde görünümünüzü buna göre güncellemek için kullanabilirsiniz.
Kaynak ( özet )
define(function () {
'use strict';
var _ = require('underscore');
var EDITABLE_STATE = 'editable',
SUBMITTING_STATE = 'submitting',
SUBMITTED_STATE = 'submitted';
var FormMixin = {
getInitialState: function () {
return {
formState: EDITABLE_STATE
};
},
componentDidMount: function () {
if (!_.isFunction(this.sendRequest)) {
throw new Error('To use FormMixin, you must implement sendRequest.');
}
},
getFormState: function () {
return this.state.formState;
},
setFormState: function (formState) {
this.setState({
formState: formState
});
},
getFormError: function () {
return this.state.formError;
},
setFormError: function (formError) {
this.setState({
formError: formError
});
},
isFormEditable: function () {
return this.getFormState() === EDITABLE_STATE;
},
isFormSubmitting: function () {
return this.getFormState() === SUBMITTING_STATE;
},
isFormSubmitted: function () {
return this.getFormState() === SUBMITTED_STATE;
},
submitForm: function () {
if (!this.isFormEditable()) {
throw new Error('Form can only be submitted when in editable state.');
}
this.setFormState(SUBMITTING_STATE);
this.setFormError(undefined);
this.sendRequest()
.bind(this)
.then(function () {
this.setFormState(SUBMITTED_STATE);
})
.catch(function (err) {
this.setFormState(EDITABLE_STATE);
this.setFormError(err);
})
.done();
}
};
return FormMixin;
});
kullanım
Bileşenin bir yöntem sağlamasını bekler: sendRequestbir Bluebird vaadi vermelidir. (Q ya da diğer sözler kitaplığı ile çalışması için onu değiştirmek önemsizdir.)
Bu gibi kolaylık yöntemler sağlar isFormEditable, isFormSubmittingve isFormSubmitted. Ayrıca istek başlaması bir yöntem sağlar: submitForm. Form düğmelerinin onClickişleyicisinden çağırabilirsiniz .