Reduxレデューサー内の状態にアクセスする方法は?


88

レデューサーがあります。新しい状態を計算するには、アクションからのデータと、このレデューサーによって管理されていない状態の一部からのデータが必要です。具体的には、以下に示すレデューサーで、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

回答:


105

これにはサンクを使用します。例を次に示します。

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

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

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


4
現在の状態がREDUX自体によってレデューサーに公開されない理由は何ですか?ディスパッチするときに、関係のないものをレデューサーに追加する必要があるのは奇妙に思えます。これは、初期状態が、現在のディスパッチ呼び出しに対する他の無関係なものの現在の状態をオーバーライドしないようにするためです
vsync 2018

10

オプションは、の使用だけでなく、より多くのロジックを記述するかcombineReducers、アクションにより多くのデータを含めることです。ReduxのFAQはこのトピックをカバーしています:

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

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


ご回答有難うございます。私はあなたがリンクしたリソースのいくつかを調査しました、そしてそうし続けるでしょう。しかし、あなたは知識があるように見えるので、あなたに質問してください。別の回答は、の使用を提案しましたthunk。これが私の問題の良い解決策になると思いますか?それが私のコードを台無しにするか、ベストプラクティスではない場合、それは私が追求したい解決策ではありませんが、これらの選択の長期的な影響を判断するのに十分な知識がありません。
kibowki 2016

3
うん、サンクは、副作用を管理し、複数のディスパッチを含む複雑なロジックを実行し、現在のアプリの状態を使用するための標準的な基本的なアプローチです。現在のアプリの状態を読み取り、条件付きでディスパッチしたり、複数のアクションをディスパッチしたり、状態の一部を取得してディスパッチされたアクションに含めたりするサンク関数を作成するのはまったく正常です。gist.github.com/markerikson/ea4d0a6ce56ee479fe8b356e099f857eに一般的なサンクパターンの例がいくつかあります。
markerikson

2

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

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

1

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

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
  }
}

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

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

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

connect(mapStateToProps)(YourReactComponent);

これで、アクションupdateProductをトリガーするreactコンポーネントで、stateOfResidenceIdを小道具として持つ必要があり、それをアクション作成者に渡すことができます。

複雑に聞こえますが、実際には関心の分離についてです。


0

あなたは使用を試みることができます:

redux-named-reducers

これにより、次のようにコード内の任意の場所で状態を取得できます。

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

ただし、最初に、アクションのペイロードとして外部状態を渡す方がよいかどうかを考えてください。


0

別の方法として、react-reduxを使用して、そのアクションを1か所でのみ必要とする場合、またはHOC(Higher 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を使用すると、返されたものが小道具に追加され、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と最高のサポートパッケージでアーカイブするよりも少ないボイラープレートでよりクリーンな構文をサポートします。また、パッケージの用途がはるかに広いにもかかわらず、reduxのドキュメントのように詳細に迷うことがないため、ドキュメントの理解が容易になります。


-1

アクションをディスパッチするときに、パラメーターを渡すことができます。この場合、accountDetails.stateOfResidenceIdアクションに渡してから、ペイロードとしてレデューサーに渡すことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.