如何访问Redux Reducer中的状态?


86

我有一个化简器,为了计算新状态,我需要操作中的数据以及该化简器未管理的部分状态数据。具体来说,在我将在下面显示的reducer中,我需要访问该accountDetails.stateOfResidenceId字段。

initialState.js:

export default {
    accountDetails: {
        stateOfResidenceId: '',
        accountType: '',
        accountNumber: '',
        product: ''
    },
    forms: {
        blueprints: [

        ]
    }
};

FormsReducer.js:

import * as types from '../constants/actionTypes';
import objectAssign from 'object-assign';
import initialState from './initialState';
import formsHelper from '../utils/FormsHelper';
export default function formsReducer(state = initialState.forms, action) {
  switch (action.type) {
    case types.UPDATE_PRODUCT: {
        //I NEED accountDetails.stateOfResidenceId HERE
        console.log(state);
        const formBlueprints = formsHelper.getFormsByProductId(action.product.id);
        return objectAssign({}, state, {blueprints: formBlueprints});
    }

    default:
      return state;
  }
}

index.js(根减速器):

import { combineReducers } from 'redux';
import accountDetails from './accountDetailsReducer';
import forms from './formsReducer';

const rootReducer = combineReducers({
    accountDetails,
    forms
});

export default rootReducer;

如何访问此字段?



8
那句话没有任何意义。减速器功能的全部目的是根据当前状态和操作来做出决策。
markerikson

Answers:


105

我将为此使用thunk,这是一个示例:

export function updateProduct(product) {
  return (dispatch, getState) => {
    const { accountDetails } = getState();

    dispatch({
      type: UPDATE_PRODUCT,
      stateOfResidenceId: accountDetails.stateOfResidenceId,
      product,
    });
  };
}

基本上,您会获得操作所需的所有数据,然后可以将该数据发送到减速器。


4
知道为什么REDUX本身不将当前状态显示给reducer吗?似乎很奇怪,在分派时我需要向减速器中添加无关的东西,以便初始状态不会覆盖其他与当前分派调用无关的东西的当前状态
vsync

10

您的选择是要么仅使用编写更多的逻辑combineReducers,要么在操作中包括更多数据。Redux常见问题解答涵盖了以下主题:

https://redux.js.org/faq/reducers/

另外,我目前正在针对Redux docs主题为“结构化减速器”的一组新页面进行工作,您可能会有所帮助。当前的WIP页面位于https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md


感谢您的回答。我已经探索了您链接的一些资源,并将继续这样做。但是,请问您一个问题,因为您似乎知识渊博。另一个答案建议使用thunk。您认为这将是解决我的问题的好方法吗?如果要弄乱我的代码或者不是最佳实践,那不是我想追求的解决方案,但是我没有足够的知识来确定这些选择的长期影响。
twilco'9

3
是的,重击是管理副作用和执行涉及多个调度并使用当前应用程序状态的复杂逻辑的标准基本方法。编写一个thunk函数来读取当前应用程序状态,并有条件地执行诸如分派,分派多个操作或获取部分状态并将其包含在分派的操作中,这是完全正常的。我在gist.github.com/markerikson/ea4d0a6ce56ee479fe8b356e099f857e上有一些常见的转换模式示例
markerikson16年

2

我不确定这种方法是否是反模式,但对我有用。在您的操作中使用咖喱函数。

export const myAction = (actionData) => (dispatch, getState) => {
   dispatch({
      type: 'SOME_ACTION_TYPE',
      data: actionData,
      state: getState()
   });
}

1

编写自己的功能完全可以实现所需的组合功能很简单:

import accountDetails from './accountDetailsReducer';
import forms from './formsReducer';

const rootReducer = (state, action) => {
        const newState = {};

        newState.accountDetails = accountDetails(state.accountDetails, action);
        newState.forms = forms(state.forms, action, state.accountDetails);

        return newState;
    };

export default rootReducer; 

您的FormReducer将是:

export default function formsReducer(state = initialState.forms, action, accountDetails) {

现在,formsReducer可以访问accountDetails。

这种方法的好处是,您只公开所需的状态片,而不是整个状态。


0

我建议您将其传递给动作创建者。因此,在某个地方,您将有一个动作创建者,它会执行以下操作:

updateProduct(arg1, arg2, stateOfResidenceId) {
  return {
    type: UPDATE_PRODUCT,
    stateOfResidenceId
  }
}

在您触发操作的地方,假设您正在使用反应,则可以使用

function mapStateToProps(state, ownProps) {
  return {
    stateOfResidenceId: state.accountdetails.stateOfResidenceId
  }  
}

并使用react-redux的connect连接到您的react组件。

connect(mapStateToProps)(YourReactComponent);

现在,在您触发操作updateProduct的react组件中,您应该将stateOfResidenceId作为道具,然后可以将其传递给您的操作创建者。

这听起来有些令人费解,但实际上是有关关注点分离的问题。


0

您可以尝试使用:

名为redux的减速器

这使您可以在代码中的任何地方获取状态,如下所示:

const localState1 = getState(reducerA.state1)
const localState2 = getState(reducerB.state2)

但是首先考虑是否最好将外部状态作为有效负载传递给操作。


0

另一种方法是,如果您使用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维护人员表示完全不赞成,但他们很好地扩展了其程序包的功能以包括这些愿望,这将为这些功能创建模式而又不支持生态系统的碎片化,这是令人印象深刻的。

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


-1

在分派动作时,您可以传递参数。在这种情况下,您可以传递accountDetails.stateOfResidenceId给操作,然后将其作为有效负载传递给reducer。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.