web-dev-qa-db-ja.com

Redux 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;

このフィールドにアクセスするにはどうすればよいですか?

64
twilco

これには thunk を使用します。以下に例を示します。

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

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

基本的に、アクションに必要なすべてのデータを取得してから、そのデータをレデューサーに送信できます。

84
Crysfel

あなたのオプションは、combineReducersの使用だけでなく、より多くのロジックを記述するか、アクションにより多くのデータを含めることです。 Redux FAQはこのトピックをカバーしています: http://redux.js.org/docs/faq/Reducers.html#reducers-share-state .

また、私は現在、Reduxのドキュメントの「Reduceの構造化」のトピックに関する新しいページのセットに取り組んでいます。現在のWIPページは https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md にあります。

9
markerikson

別の方法として、react-reduxを使用し、そのアクションを1か所でのみ必要とする場合ORは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を使用すると、返されるものがpropに追加され、mapStateとmapDispatchはmergePropsの引数を提供するためだけに使用されます。つまり、言い換えると、この関数はこれをコンポーネントの小道具(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-maintainersがパッケージの機能を拡張してそのような希望を適切に含めることで、エコシステムの断片化をサポートすることなくこれらの機能のパターンを作成することを示す完全な不承認は印象的です。

頑固ではないVuexのようなパッケージは、アンチパターンが迷子になるため、アンチパターンを悪用する人々に多くの問題を抱えていますが、reduxと最高のサポートパッケージでアーカイブするよりも少ない定型で、よりクリーンな構文をサポートします。また、パッケージの汎用性が非常に高いにもかかわらず、reduxsドキュメンテーションが行う傾向があるような詳細に迷子にならないため、ドキュメンテーションは理解しやすくなります。

0
Sam96

アクションクリエーターに渡すことをお勧めします。そのため、どこかに次のようなことを行うアクションクリエーターがいます。

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

アクションをトリガーする場所で、reactを使用していると仮定すると、使用できます

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

そして、react-reduxの接続を使用して、reactコンポーネントに接続します。

connect(mapStateToProps)(YourReactComponent);

これで、アクションupdateProductをトリガーする反応コンポーネントで、stateOfResidenceIdをプロップとして持つ必要があり、アクション作成者に渡すことができます。

複雑に聞こえますが、実際には懸念の分離に関するものです。

0
Xing Wang

あなたが使用しようとすることができます:

redux-named-reducers

これにより、コードのどこにでも状態を取得できます:

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

ただし、アクションのペイロードとして外部状態を渡す方が良い場合は、まず考えてください。

0
miles_christian

このアプローチがアンチパターンであるかどうかはわかりませんが、うまくいきました。アクションでカリー化された関数を使用します。

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

必要なことを正確に行う独自の結合関数を作成するのは簡単です。

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
GhostEcho