在尝试将我的大脑围绕在 React 和 Flux 上时,我很难决定将我所谓的“模型助手”方法放在哪里更有意义。
例如,假设 Store 中包含一个“Person”实体,并且该 Person 具有“名字”和“姓氏”,那么放置“全名”助手最合乎逻辑的位置简单地将两者连接在一起的方法?我的直觉说最好在 Store 中有“全名”,但我不确定。如果是这样,它会是一个更新 store 中这个值的 Action,还是应该在 Store 本身内计算它?
有没有可以接受的地方放置这种功能?
谢谢!
在尝试将我的大脑围绕在 React 和 Flux 上时,我很难决定将我所谓的“模型助手”方法放在哪里更有意义。
例如,假设 Store 中包含一个“Person”实体,并且该 Person 具有“名字”和“姓氏”,那么放置“全名”助手最合乎逻辑的位置简单地将两者连接在一起的方法?我的直觉说最好在 Store 中有“全名”,但我不确定。如果是这样,它会是一个更新 store 中这个值的 Action,还是应该在 Store 本身内计算它?
有没有可以接受的地方放置这种功能?
谢谢!
为了使事情易于管理,特别是如果您有许多商店和大型组件树,请尝试关注商店和组件的功能:
我会尽量避免在组件树中操作数据。并建议任何组件中的任何数据props始终来自商店。它们从更高的组件传递下来,但不会在此过程中被操纵。
如果辅助函数只处理数据(例如计算组中的总人数),则将它们放在存储中。如果他们处理呈现逻辑(例如页面上第一人称的字体大小应该更大),请将它们放在一个单独的地方。我将它们放在单独的实用程序中进行导入。但仅在尽可能低的组件上调用这些函数。
这样,您的代码就更易于维护了。
数据助手和表示逻辑之间有很多灰色地带,所以你在这种情况下的选择很难说。但是只要您始终如一地应用自己的逻辑,您的代码就可以保持可管理性。
这样,当组件给您带来问题时,将更容易跟踪 props 到它们的来源,或者应用于组件中这些 props 的函数代码。
所以也许是一个具有全名函数的高阶组件,但我不会让高阶组件创建一个新的props。
所以 store 保存了应用程序的数据和业务逻辑,我看到这个 helper 就像一个应该在你的 store 内发生的动作。您不需要更新全名的操作,一旦第一个和第二个名称可用,它应该由商店本身连接。
除了@Christian 的回答(我同意)之外,您还可以使用以下object-assign
module在商店中使用通用助手:https : //www.npmjs.com/package/object-assign
这是我的一个商店的部分示例,其中包含帮助方法(例如isAuthenticated
和getUsername
)object-assign
用于将 组合StatusMixin
到每个商店中:
var AuthStore = assign({}, StatusMixin, EventEmitter.prototype, {
isAuthenticated: function () {
return _data.get(TOKEN_KEY) ? true : false;
},
getUsername() {
return _data.get(USERNAME_KEY);
},
getToken() {
return _data.get(TOKEN_KEY);
},
invalidate() {
_data = _data.clear();
this.setStatus(''); //this method is from the StatusMixin!
this.emitChange(Constants.CHANGED);
},
emitChange: function() {
LocalStorage.set(Constants.ls.AUTH_STORE, {
auth_token: _data.get(TOKEN_KEY),
username: _data.get(USERNAME_KEY)
});
this.emit(Constants.CHANGED);
},
addChangeListener: function(callback) {
this.on(Constants.CHANGED, callback);
},
removeChangeListener: function(callback) {
this.removeListener(Constants.CHANGED, callback);
},
getState: function() {
return _data;
}
});
和(完整的) StatusMixin
'use strict';
var logger = require('../../util/Logger');
var StatusMixin = {
_status: '',
getStatus: function() {
return this._status;
},
setStatus(status) {
this._status = status;
}
};
module.exports = StatusMixin;
现在我可以调用AuthStore.setStatus(Constants.request.PENDING);
(我对每个 Store 都这样做)而无需setStatus
在每个 Store 上编写方法。
通常,此处的“最佳实践”是创建一个高阶组件,该组件提供辅助函数或连接的全名作为需要此修改值的组件的props。
function giveFullName(Component) {
const ComponentWithFullName = React.createClass({
render() {
return <Component {...this.props} fullName={this.props.firstName+" "+this.props.lastName} />;
}
});
return ComponentWithFullName;
};
var PersonPage = React.createClass({
render() {
var { name } = this.props.fullName; // get fullName from props
return <div>{'Hello '+(name ? name : 'Mystery Stranger')}</div>;
}
});
PersonPage = ComponentWithFullName(PersonPage)
});
我不同意@cristian 的回答,因为 ReactJS 的优势之一是它对应用程序信息流的关注点分离和推理的简易性。如果我们在 store 中放置一个 helper 方法,那么我们不知道什么时候会看到全名,它是来自 store 的全名,还是一个组件通过连接来自同一个 store 的名字和姓氏而创建的全名. 但是,如果不把这个全名函数放在 store 中,那么我们就知道任何全名都来自一个组件。创建可以提供此功能的高阶组件实现了相同的 DRY 原则,同时保持了清晰推理值/UI 元素来自何处的能力。
请参阅https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750了解有关 React 中的 HoC 与 Mixins 的更多信息,以及为什么您应该偏爱 HoC。