当您识别模式时,您可以创建抽象。这里的模式是需要以简单的方式处理不断变化的道具。我一直在考虑这个问题......这是我迄今为止想出的。
propUpdates: {
propName: {
onMount: function(to, el, config){}
onChange: function(from, to, el, config){},
idempotent: false,
compare: 'default'
}
}
它可能仍然很冗长,但它更具声明性,不需要大量的 if 语句和比较。jsbin
var Test = React.createClass({
mixins: [propUpdatesMixin],
propUpdates: {
text: {
onChange: function(from, to, el){
el.textContent = to;
},
idempotent: true
}
},
render: function(){
return <div />;
}
});
onChange 仅在属性实际更改时调用。默认情况下,这是比较的,===
但是您可以指定一个compare
“浅”、“深”或一个函数,该函数采用新旧 prop 值并在它们相等时返回 true。
如果idempotent
为真,则调用 onChange 代替 onMount,第一个参数为undefined
. onChange 和 onMount 内部this
是组件实例。要获取具有 onChange/onMount/etc 属性的对象,请使用最后一个参数 (config)。
有时您需要更多控制,例如当您需要对多个道具的变化做出反应时。
componentDidUpdate: function(prevProps){
var changes = this.getPropsChanges(prevProps, this.props);
if (changes.text.changed && changes.color.changed) {
// ...
}
}
的返回getPropsChanges
是将道具名称映射到更改对象。更改对象具有以下结构:
{
changed: Boolean,
from: Any,
to: Any,
name: String (prop name)
config: {onMount,onChange,idempotent,compare}
}
mixin 旨在不妨碍您。您可以混合和匹配策略。它只需要一个 propUpdates,但它可以是{}
. 您仍然可以编写自己的 componentDidMount 并仅将 propUpdates 用于 onChange,或者仅将 propUpdates 用于 onMount 并编写自己的 componentWillUpdate,或者将 onChange 用于一个 prop,将 onMount 用于另一个,将幂等 onChange 用于第三个,然后做一些事情在 componentDidMount 和 componentDidUpdate 中。
玩弄 jsbin看看它是否符合您的需要。为了完整起见,这里是 mixin 的完整代码。
var comparisons={"shallow":function(a,b){return Object.keys(a).every(function(key){return a[key]!==b[key]})},"deep":function(a,b){return!_.isEqual(a,b)},"default":function(a,b){return a!==b}};var EACH_PROP="__propUpdatesMixin_eachProp__";var PROPS="propUpdates";var propUpdatesMixin={};
propUpdatesMixin.componentDidMount=function(){var el=this.getDOMNode();this[EACH_PROP](function(propName,config,propValue){if(config.onMount)config.onMount.call(this,propValue,el,config);else if(config.onChange&&config.idempotent)config.onChange.call(this,undefined,propValue,el,config)},this.props)};
propUpdatesMixin.componentDidUpdate=function(prevProps){var el=this.getDOMNode();var changes=this.getPropsChanges(prevProps,this.props);Object.keys(changes).forEach(function(propName){var change=changes[propName];if(change.changed&&change.config.onChange)change.config.onChange.call(this,change.from,change.to,el,change.config)},this)};
propUpdatesMixin.getPropsChanges=function(propsA,propsB){var updates={};this[EACH_PROP](function(propName,config,a,b){var compare=typeof config.compare==="function"?config.compare:comparisons[config.compare]?comparisons[config.compare]:comparisons["default"];var changed=compare(a,b);updates[propName]={changed:changed,from:a,to:b,name:propName,config:config}},propsA,propsB);return updates};
propUpdatesMixin[EACH_PROP]=function(fn,propsA,propsB){propsA=propsA||{};propsB=propsB||{};Object.keys(this[PROPS]).map(function(propName){return fn.call(this,propName,this[PROPS][propName],propsA[propName],propsB[propName])},this)};