我开始在Backbone项目中使用Facebook React,到目前为止一切进展顺利。
但是,我注意到一些重复出现在我的React代码中。
例如, 我有几个 状态为INITIAL
,SENDING
和
的类似表单的小部件SENT
。当按下按钮时,需要验证表单,提出请求,然后更新状态。this.state
当然,状态与字段值一起保存在React
中。
如果这些是Backbone视图,我会提取一个名为的基类,FormView
但 我的印象是React既不认可也不支持子类共享视图逻辑
(如果我错了,请纠正我)。
我已经看到了两种在React中重用代码的方法:
我是否正确认为Mixins和容器在React中优先于继承?这是故意设计的决定吗? 在第二段的“表单小部件”示例中使用混合或容器组件是否更有意义?
这里有一个要点FeedbackWidget
,并JoinWidget
在其当前状态。它们具有相似的结构,相似的beginSend
方法,并且都需要某种验证支持(尚不存在)。
更新:这个答案已经过时了。如果可以的话,请远离mixin。我警告过你!
Mixins已死。 万岁组成
首先,我尝试为此使用子组件并提取FormWidget
和InputWidget
。但是,我中途放弃了这种方法,因为我想更好地控制生成的input
s及其状态。
有两篇对我最有帮助的文章:
事实证明,我只需要编写两个(不同的)mixin:ValidationMixin
和FormMixin
。
这是我分开它们的方式。
验证mixin添加了方便的方法,可以在状态的某些属性上运行验证器函数,并将“错误的”属性存储在state.errors
数组中,以便突出显示相应的字段。
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;
});
ValidationMixin
有三种方法:validate
,hasError
和resetError
。
它期望类定义validators
对象,类似于propTypes
:
var JoinWidget = React.createClass({
mixins: [React.addons.LinkedStateMixin, ValidationMixin, FormMixin],
validators: {
email: Misc.isValidEmail,
name: function (name) {
return name.length > 0;
}
},
// ...
});
当用户按下提交按钮时,我致电validate
。调用validate
将运行每个验证器,并填充this.state.errors
一个数组,该数组包含验证失败的属性的键。
在我的render
方法中,我用来hasError
为字段生成正确的CSS类。当用户将焦点放在该字段内时,我会调用resetError
以删除错误突出显示,直到下一次validate
调用为止。
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)} />
);
}
表单混合处理表单状态(可编辑,提交,已提交)。您可以使用它在发送请求时禁用输入和按钮,并在发送请求时相应地更新视图。
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;
});
它期望组件提供一种方法:sendRequest
,该方法应返回Bluebird
Promise。(修改它以与Q或其他Promise库一起使用是微不足道的。)
它提供了便利的方法,例如isFormEditable
,isFormSubmitting
和isFormSubmitted
。它还提供了启动请求的方法:submitForm
。您可以从表单按钮的onClick
处理程序中调用它。
用代码度量和提取方法模式进行目的明确的重构 在 追求代码质量 的前一期中,学习了如何用代码度量客观地测量代码质量。这个月,Andrew Glover 将介绍如何使用相同的度量方法和提取方法模式进行有针对性的重构。 在我上中学的时候,有一位英语教师说:“写作就是重写别人已经 重写过的东西。” 直到大学,我才真正理解了他这句话的意思。而且,当我自觉地采用这个实践的时候,就开始喜欢上了写作。我开始为我写
我在执行时出现了这个错误: 我错过了什么?
我将马上讨论我真正的问题/问题,是否有任何方法访问HttpMessageConverter内部控制器处理程序方法上的注释?我很确定答案是否定的(在浏览了Spring的源代码之后)。 在使用MappingJacksonHttpMessageConverter时,是否有其他方法使用Jackson Mixins配对?我已经基于MappingJacksonHttpMessageConverter实现了自己
我的应用程序中有3个枚举器类。所有3个类都有2个重复的方法,我们希望这些方法在我们实现的每个枚举中都可用。 这些方法中唯一更改的部分是EnumClass,它是每个enum的类。 第一个方法将打印枚举类的所有可能值,第二个方法将返回true/false(如果给定字符串可以放入枚举类中)。 我试图实现实现这些方法的接口,但我不能使用值(),因为它不是Enum API的一部分。我不能将这些方法与每个类具
我的工作细节如下。 服务器和客户端证书生成(不通过CA进行证书签名,只需自签名) (1)生成服务器密钥和证书。 (2)生成客户端密钥和证书。$openssl genrsa-des3-退出客户端.key 2048 $openssl请求-新建-密钥客户端.密钥-退出客户端.CSR $cp Client.Key Client.Key.Origin //server.c //客户端.c 下面是输出结果。
问题内容: 我发现自己一次又一次地重复相同的代码片段,是否有可能在AngularJS中执行类似的操作: 上面的输出将是: 我不一定要寻找确切的“ ng:include”解决方案或模式,而是会减少模板中重复次数的方法。 问题答案: 这应该是您想要的。 脚本和ng- include的 文档。