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

Posted

技术标签:

【中文标题】模型助手在 React/Flux 中属于哪里?【英文标题】:Where do model helpers belong in React/Flux? 【发布时间】:2015-12-20 00:30:14 【问题描述】:

在尝试围绕 React 和 Flux 进行思考时,我很难决定将我称之为“模型助手”的方法放在哪里有意义。

例如,假设 Store 中包含一个“Person”实体,并且假设这个 Person 有一个“名字”和一个“姓氏”,那么在哪里放置“完整name" 简单地将两者连接在一起的辅助方法?我的直觉说最好在商店中使用“全名”,但不确定。如果是这样,它会是一个 Action 更新 store 中的这个值,还是应该在 Store 本身内计算?

有没有一个可以接受的地方来放置这种功能?

谢谢!

【问题讨论】:

【参考方案1】:

为了保持事情的可管理性,特别是如果你有很多商店和一个大的组件树,试着集中你的商店和组件的功能:

    存储用于 a) 存储数据(名字、姓氏,非派生数据),以及 b) 为组件提供数据(包括派生数据)。 组件用于向用户呈现 a) 数据,以及 b) 与数据交互的锚。

我会尽量避免在组件树中操作数据。并建议任何组件中的任何数据道具始终来自商店。它们是从更高的组件传下来的,但不会在此过程中被操纵。

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

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

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

这样,当一个组件给你问题时,更容易追踪 props 的来源,或者你的组件中应用于这些 props 的函数代码。

所以也许是一个具有全名函数的高阶组件,但我不会让高阶组件创建一个新的道具。

【讨论】:

【参考方案2】:

所以 store 保存了应用程序的数据和业务逻辑,我看到这个帮助器就像一个应该在你的 store 中发生的操作。您不需要更新全名的操作,一旦第一个和第二个名称可用,它应该由商店本身连接。

【讨论】:

【参考方案3】:

除了@Christian 的回答(我同意)之外,您还可以通过使用object-assign 模块在商店中使用通用助手:https://www.npmjs.com/package/object-assign

这是我的一个商店的部分示例,它带有辅助方法(例如isAuthenticatedgetUsername),使用object-assignStatusMixin 组合到每个商店中:

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 调用),而无需在每个 Store 上编写 setStatus 方法。

【讨论】:

【参考方案4】:

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

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。

【讨论】:

以上是关于模型助手在 React/Flux 中属于哪里?的主要内容,如果未能解决你的问题,请参考以下文章

在哪里放置不是模型、视图、控制器或助手的 Rails 代码?

React + Webpack:在哪里配置 REST 端点

React Flux 从远程服务获取 Api 数据

模型上的操作在应用程序设计模式中属于哪里?

添加/编辑模型的代码属于哪里?模型或控制器

仅更新 JSON 对象的一个​​值并使用 React Flux 保留旧的值