如何在 Immutablejs 和 Redux 以及 Flux 和 React 中设置 Ember 之类的计算属性

How to setup Ember like computed properties in Immutablejs and Redux and Flux and React

我习惯于在 Ember Object Model 中计算属性。这是指定依赖于其他属性的计算属性的便捷方式。

fullName 取决于 firstNamelastName,我可以将计算属性设置为函数 computeProperties 并在每次创建时调用 computeProperties改变。

示例:

function computeFullName(state) {
  const fullName = state.get('firstName') + state.get('lastName');
  const nextState = state.set('fullName', fullName);
  return nextState;
}

function computeProperties(state) {
  const nextState = computeFullName(state);
  return nextState;
}

// store action handler
[handleActionX](state) {

  let nextState = state.set('firstName', 'John');
  nextState = state.set('lastName', 'Doe');

  nextState = computeProperties(nextState);

  return nextState;
}

有没有一种方法可以自动设置计算属性,这样我就不必每次都调用额外的函数。在 Redux 或 ImmutableJS 中。

要创建计算属性,您可以使用独立的可观察库 mobservable

var user = mobservable.props({
  firstName: 'John',
  lastName: 'Doe',
  fullName: function() {
    return this.firstName + this.lastName
  }
});

var nameViewer = mobservable.ObservingComponent(React.createClass({
   render: function() {
       return (<span>{user.fullName}</span>)
   }
});

这应该是它的要点,现在对 user.firstName 或 lastName 的任何更改都将重新呈现您的 nameViewer 组件。您可以进一步将其与 redux 等 flux 实现结合起来以更改数据,并将用户本身推送到您的组件树中。但请注意,用户对象本身是 not 不可变的(在那种情况下,它毕竟不会被观察到 ;-))另请参阅此 trivial and slightly more interesting 小提琴以获取一些示例。

查看 reselect。可组合的纯函数,用于高效计算来自商店的派生数据。 Afaik 计划在某个阶段将 reselect 的选择器滚动到 Redux 核心中,如果它们被证明很受欢迎。自述文件底部也有一个使用 ImmutableJS 的示例。

这里是 Redux 作者!

是要走的路。我认为我们不会将它包含在核心中,因为 reselect 可以很好地完成它的工作,我们可以接受它作为一个单独的库。

我想说明几点:

  • 即使重新选择,您也不想在减速器中计算数据。选择器应该在 on reducer 管理的状态下运行。换句话说,选择器是你的 Redux 存储状态和你的组件之间的步骤——它们不在你的 reducer 中。保持 Redux 状态规范化是很重要的,这样它就很容易更新。

  • 我们实际上鼓励您定义选择器 以及 相关的缩减器,这样 当您更改状态形状时,您不会必须更改您的组件——他们将改用选择器。您可以在 Redux folder of Flux Comparison

  • 中看到这方面的示例
  • 我们有一个documentation page introducing reselect and describing how to use it for computing derived data。看看吧。

这样的事情怎么样?

export const getWidgetsWithComputedProps = widgets => {
  return widgets.map(w => getWidgetWithComputedProps(w));
};

export const selectWidgetType = widget => {
  switch (widget.type) {
    case 'line':
      return 'time-series';
    case 'pie':
    case 'bar':
      return 'cross-sectional';
    default:
      console.warn('Back up: that type of widget does not exist!', widget.type);
      return null;
  }
};

export const getWidgetWithComputedProps = createSelector(
  widget => widget,
  selectWidgetType,
  (widget, _type) => {
    return {...widget, _type}
  }
);