Javascript 模型助手在React/Flux中属于哪里?

Javascript 模型助手在React/Flux中属于哪里?,javascript,reactjs,reactjs-flux,flux,Javascript,Reactjs,Reactjs Flux,Flux,当我试图将我的大脑包裹在反应和流量上时,我很难决定将我称之为“模型助手”的方法放在哪里是有意义的 例如,假设一个存储中包含一个“Person”实体,并且该实体有一个“名字”和一个“姓氏”,那么将这两个实体连接在一起的“全名”助手方法放在哪里最合理?我的直觉告诉我最好在商店里有“全名”,但我不确定。如果是这样,是更新存储中的该值的操作,还是应该在存储本身中计算该值 有没有一个公认的地方可以放置这种功能 谢谢 因此,存储区保存了应用程序的数据和业务逻辑,我认为助手就像应该在存储区内执行的操作一样。您

当我试图将我的大脑包裹在反应和流量上时,我很难决定将我称之为“模型助手”的方法放在哪里是有意义的

例如,假设一个存储中包含一个“Person”实体,并且该实体有一个“名字”和一个“姓氏”,那么将这两个实体连接在一起的“全名”助手方法放在哪里最合理?我的直觉告诉我最好在商店里有“全名”,但我不确定。如果是这样,是更新存储中的该值的操作,还是应该在存储本身中计算该值

有没有一个公认的地方可以放置这种功能


谢谢

因此,存储区保存了应用程序的数据和业务逻辑,我认为助手就像应该在存储区内执行的操作一样。您不需要更新全名的操作,只要第一个和第二个名称可用,它就应该由存储本身连接起来

除了@Christian的答案(我同意),您还可以使用
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)
(我为每个存储区执行此操作),而不在每个存储区上写入
setStatus
方法。

通常,这里的“最佳实践”是创建一个更高阶的组件,为需要此修改值的组件提供帮助函数或连接的全名作为道具

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)
});
函数名(组件){
const ComponentWithFullName=React.createClass({
render(){
返回;
}
});
返回具有完整名称的组件;
};
var PersonPage=React.createClass({
render(){
var{name}=this.props.fullName;//从props获取fullName
返回{'Hello'+(name?name:'神秘陌生人')};
}
});
PersonPage=具有全名的组件(PersonPage)
});
我不同意@cristian的回答,因为ReactJS的优点之一是它能够很好地分离关注点,并且易于对应用程序信息流进行推理。如果我们在存储中放置了一个helper方法,那么我们不知道什么时候会看到全名,它是存储中的全名,还是组件通过连接同一存储中的名字和姓氏而创建的全名。但是,如果不将这个全名函数放在存储中,那么我们知道任何全名都来自组件。创建一个能够提供此功能的高阶组件可以实现相同的DRY原则,同时保持清晰地解释值/UI元素来自何处的能力


有关React中HoC与Mixin的更多信息,以及为什么您可能会喜欢HoC,请参阅。

为了保持事情的可管理性,特别是如果您有许多存储和大型组件树,请尝试关注存储和组件的功能:

  • 存储用于a)存储数据(名、姓、非派生数据),以及b)为组件提供数据(包括派生数据)
  • 组件用于向用户呈现a)数据,以及b)锚定与数据的交互
  • 我会尽量避免在组件树中操纵数据。并建议任何组件中的任何数据道具始终源自存储。它们是从更高的组件传递下来的,但不是一路上操纵的

    如果helper函数只处理数据(例如计算组中的总人数),则将其放入存储区。 如果他们处理呈现逻辑(例如,页面上第一个人的字体大小应该更大),请将他们放在单独的位置。我将它们放在单独的实用程序中进行导入。 但是只在尽可能低的组件上调用这些函数

    这样,您的代码就更易于维护

    在数据助手和表示逻辑之间有很多灰色区域,因此在这种情况下很难说您的选择。但只要您一致地应用自己的逻辑,您的代码就会保持可管理性

    这样,当组件向您提供问题时,将更容易跟踪道具的源代码,或者跟踪应用于组件中这些道具的功能代码

    因此,可能是一个具有全名函数的高阶组件,但我不会让高阶组件创建新的道具