Redux:在reducer函数中调用store.getState(),这是一种反模式吗?

时间:2016-07-23 18:01:04

标签: javascript redux

我想知道,有时候我的减速机需要另一台减速机的信息。例如,我有这个减速器:

import * as ActionTypes from '../actions/action_type_constants';
import KeyCode from 'keycode.js/index';
import {store} from "../index";
import {mod} from "../pure_functions";

export function selectedCompletion(state = 0, action) {
  if (action.type === ActionTypes.arrowKeyPressed) {
    const completionsLength = store.getState().completions.data.length;
    if (action.keyCode === KeyCode.UP) {
      return mod(state - 1, completionsLength);
    } else if (action.keyCode === KeyCode.DOWN) {
      return mod(state + 1, completionsLength);
    }
  }
  return state;
}

我在函数的第二行调用store.getState,因为否则我无法正确确定索引。

我可以重构这个和另一个减速器,这样它就变成了一个大的减速器,但为了便于阅读,我更喜欢这个选项。

如果我在减速器中使用这种调用store.getState()的模式,我不确定是否会以某种方式解决问题。

3 个答案:

答案 0 :(得分:16)

是的,这是绝对反模式。 Reducer功能应该是" pure",并且只能基于它们的直接输入(当前状态和动作)。

Redux常见问题解答在the FAQ on sharing state between reducers中讨论了这类问题。基本上,您应该编写一些自定义的reducer逻辑,传递所需的其他信息,或者将更多信息添加到您的操作中。

我还为Redux文档编写了一个名为Structuring Reducers的部分,该部分讨论了与reducer逻辑相关的一些重要概念。我鼓励你仔细阅读。

答案 1 :(得分:0)

您想要的模式是合成的一种情况,因为您正在根据来自其他域的其他现有状态(在reducer域的意义上)准备新状态。在Redux文档中,标题为Computing Derived States的主题下提供了一个示例。

但是请注意,他们的样本组合了容器中的状态,而不是化合器中的状态;仍提供所需的组件。

答案 2 :(得分:0)

对于这些来此页面的人,他们想知道如何将大型应用程序升级到redux 4.0而又不修改其完整的状态管理,因为在简化器中禁止了getState等:

虽然我像作者一样对这种反模式表示不满,但是当您意识到他们在没有任何技术原因且没有选择退出的情况下禁止使用这些功能时,却使人们无法进行更新,而不幸的是拥有代码库,广泛使用这种反模式...好吧,我提出了合并请求,以添加具有重型后卫的退出,但该请求立即被关闭。

因此,我创建了一个redux分支,它允许在创建商店时禁用禁令:

https://www.npmjs.com/package/free-redux

对于其他任何人,请使用此处的示例之一或我在another question中提供的方式:

另一种方法,如果您使用react-redux并且只需要在一个地方执行该操作,或者创建HOC很好(更高的oder组件,则实际上不需要了解重要的内容可能会使您的html膨胀)您需要访问的任何地方都是使用mergeprops,并将附加参数传递给操作:

const mapState = ({accountDetails: {stateOfResidenceId}}) => stateOfResidenceId;

const mapDispatch = (dispatch) => ({
  pureUpdateProduct: (stateOfResidenceId) => dispatch({ type: types.UPDATE_PRODUCT, payload: stateOfResidenceId })
});

const mergeProps = (stateOfResidenceId, { pureUpdateProduct}) => ({hydratedUpdateProduct: () => pureUpdateProduct(stateOfResidenceId )});

const addHydratedUpdateProduct = connect(mapState, mapDispatch, mergeProps)

export default addHydratedUpdateProduct(ReactComponent);

export const OtherHydratedComponent = addHydratedUpdateProduct(OtherComponent)

当使用mergeProps时,返回的内容将添加到props中,mapState和mapDispatch仅用于提供mergeProps的参数。因此,换句话说,此函数会将其添加到组件属性(打字稿语法)中:

{hydratedUpdateProduct: () => void}

(请注意,该函数实际上会返回操作本身,而不是void,但是在大多数情况下,您会忽略它。)

但是您可以做的是:

const mapState = ({ accountDetails }) => accountDetails;

const mapDispatch = (dispatch) => ({
  pureUpdateProduct: (stateOfResidenceId) => dispatch({ type: types.UPDATE_PRODUCT, payload: stateOfResidenceId })
  otherAction: (param) => dispatch(otherAction(param))
});

const mergeProps = ({ stateOfResidenceId, ...passAlong }, { pureUpdateProduct, ... otherActions}) => ({
  ...passAlong,
  ...otherActions,
  hydratedUpdateProduct: () => pureUpdateProduct(stateOfResidenceId ),
});

const reduxPropsIncludingHydratedAction= connect(mapState, mapDispatch, mergeProps)

export default reduxPropsIncludingHydratedAction(ReactComponent);

这将为道具提供以下内容:

{
  hydratedUpdateProduct: () => void,
  otherAction: (param) => void,
  accountType: string,
  accountNumber: string,
  product: string,
}

总体上,尽管redux-maintainers表示完全不赞成,但他们很好地扩展了其软件包的功能以包含这些愿望,这将为这些功能创建模式,而无需支持生态系统的碎片化, / p>

像Vuex这样不那么顽固的软件包在人们滥用反模式方面会遇到很多问题,因为它们丢失了,同时还支持一种更简洁的语法,比您使用redux和最好的支持软件包进行归档要少。而且,尽管该软件包具有更多用途,但易于理解,因为它们不会像reduxs文档那样在细节中迷失方向。