繁体   English   中英

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

[英]Redux: Calling store.getState() in a reducer function, is that an anti pattern?

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

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,否则我无法正确确定索引。

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

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

是的,这绝对是一种反模式。 减速器功能应该是“纯粹的”,并且仅基于它们的直接输入(当前状态和动作)。

Redux FAQ在关于reducers之间共享状态的 FAQ中讨论了这类问题。 基本上,您应该编写一些自定义的reducer逻辑,传递所需的其他信息,或将更多信息添加到您的操作中。

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

您想要的模式是组合的情况,因为您正在准备基于其他域(在reducer域意义上)的其他现有状态的新状态。 在Redux文档中,在题为计算派生状态的主题下提供了一个示例。

请注意,他们的样本将容器中的状态组合在一起 - 而不是在减速器中; 然后喂养需要它的组件。

对于这些来到这个页面想知道如何将他们的大型应用程序升级到redux 4.0而不改进他们的完整状态管理,因为getState等在reducers中被禁止:

虽然我和作者一样,反对这种反模式,当你意识到他们在没有任何技术原因且没有选择退出的情况下禁止使用这些功能时,让没有更新的人不幸拥有广泛使用这个的代码库反模式...好吧,我做了一个合并请求,用重型警卫添加一个选择退出,但它只是立即关闭。

所以我创建了一个redux fork,允许在创建存储时禁用禁令:

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

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

另一种方法,如果你使用react-redux并且只在一个地方需要这个动作,或者可以创建一个HOC(更高级的组件,真的不需要理解重要的东西,这可能会使你的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提供参数。 所以,换句话说,这个函数会将它添加到你的组件props(typescript语法):

{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维护者表示扩展其软件包的功能,以便以良好的方式包含这些愿望,这将为这些功能创建一个模式,而不支持生态系统的碎片化,令人印象深刻。

像Vuex这样不那么顽固的软件包并没有人们滥用反模式的问题,因为他们迷路了,而支持一种更简洁的语法,用更少的样板文件比用everx和最好的支持软件包存档更少。 尽管这个包更加通用,但是文档更容易理解,因为它们不会像reduxs文档那样迷失在细节中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM