Cập nhật: câu trả lời này đã lỗi thời. Tránh xa các mixins nếu bạn có thể. Tôi đã cảnh báo bạn!
Mixins đã chết. Thành phần sống lâu
Lúc đầu, tôi đã thử sử dụng các thành phần con cho việc này và giải nén FormWidget
và InputWidget
. Tuy nhiên, tôi đã từ bỏ cách tiếp cận này nửa chừng vì tôi muốn kiểm soát tốt hơn đối với input
s được tạo và trạng thái của chúng.
Hai bài viết giúp tôi nhiều nhất:
Hóa ra tôi chỉ cần viết hai mixin (khác nhau): ValidationMixin
và FormMixin
.
Đây là cách tôi tách chúng ra.
Xác nhậnMixin
Xác thực mixin thêm các phương thức tiện lợi để chạy các chức năng trình xác nhận của bạn trên một số thuộc tính trạng thái của bạn và lưu trữ các thuộc tính Lỗi lỗi trong một state.errors
mảng để bạn có thể đánh dấu các trường tương ứng.
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;
});
Sử dụng
ValidationMixin
có ba phương pháp: validate
, hasError
và resetError
.
Nó mong đợi lớp định nghĩa validators
đối tượng, tương tự như propTypes
:
var JoinWidget = React.createClass({
mixins: [React.addons.LinkedStateMixin, ValidationMixin, FormMixin],
validators: {
email: Misc.isValidEmail,
name: function (name) {
return name.length > 0;
}
},
// ...
});
Khi người dùng nhấn nút gửi, tôi gọi validate
. Một cuộc gọi đến validate
sẽ chạy từng trình xác nhận và điền this.state.errors
vào một mảng có chứa các khóa của các thuộc tính không xác thực.
Trong render
phương thức của tôi , tôi sử dụng hasError
để tạo lớp CSS chính xác cho các trường. Khi người dùng đặt tiêu điểm bên trong trường, tôi gọi resetError
để xóa lỗi tô sáng cho đến validate
cuộc gọi tiếp theo .
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
Mẫu mixin xử lý trạng thái biểu mẫu (có thể chỉnh sửa, gửi, gửi). Bạn có thể sử dụng nó để vô hiệu hóa các đầu vào và nút trong khi yêu cầu đang được gửi và để cập nhật chế độ xem của bạn tương ứng khi nó được gửi.
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;
});
Sử dụng
Nó hy vọng thành phần sẽ cung cấp một phương thức : sendRequest
, sẽ trả về một lời hứa Bluebird. (Việc sửa đổi nó để làm việc với Q hoặc thư viện lời hứa khác là chuyện nhỏ.)
Nó cung cấp các phương thức tiện lợi như isFormEditable
, isFormSubmitting
và isFormSubmitted
. Nó cũng cung cấp một phương thức để khởi động yêu cầu : submitForm
. Bạn có thể gọi nó từ onClick
trình xử lý nút biểu mẫu .