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 FormWidgetvà 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 inputs đượ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): ValidationMixinvà 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.errorsmả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
ValidationMixincó ba phương pháp: validate, hasErrorvà 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 validatesẽ chạy từng trình xác nhận và điền this.state.errorsvà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 renderphươ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 validatecuộ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, isFormSubmittingvà 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ừ onClicktrình xử lý nút biểu mẫu .