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

10

옵션은를 사용하는 것 외에 더 많은 논리를 작성 combineReducers하거나 작업에 더 많은 데이터를 포함하는 것입니다. Redux FAQ는이 주제를 다룹니다.

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

또한 저는 현재 "Structuring Reducers"주제에 대한 Redux 문서의 새로운 페이지 세트를 작업 중이며 도움이 될 것입니다. 현재 WIP 페이지는 https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md에 있습니다.


답변 해 주셔서 감사합니다. 귀하가 링크 한 몇 가지 리소스를 살펴 보았으며 계속해서 그렇게 할 것입니다. 그러나 당신은 지식이있는 것 같아서 질문하십시오. 또 다른 대답은 thunk. 이것이 내 문제에 대한 좋은 해결책이라고 생각하십니까? 내 코드를 엉망으로 만들거나 모범 사례가 아니라면 추구하고 싶은 해결책은 아니지만 이러한 선택의 장기적인 효과를 결정할만큼 충분히 지식이 없다고 생각합니다.
kibowki

3
썽 크는 부작용을 관리하고 다중 디스패치를 ​​포함하고 현재 앱 상태를 사용하는 복잡한 논리를 실행하는 표준 기본 접근 방식입니다. 현재 앱 상태를 읽고 조건부로 디스패치, 여러 작업을 디스패치 또는 상태의 일부를 가져와 디스패치 된 작업에 포함시키는 썽크 함수를 작성하는 것은 완전히 정상입니다. gist.github.com/markerikson/ea4d0a6ce56ee479fe8b356e099f857e 에 일반적인 썽크 패턴의 몇 가지 예가 있습니다.
markerikson

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

액션을 트리거하는 곳에서 react를 사용한다고 가정하면

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

react-redux의 연결을 사용하여 반응 구성 요소에 연결하십시오.

connect(mapStateToProps)(YourReactComponent);

이제 updateProduct 작업을 트리거하는 반응 구성 요소에서 stateOfResidenceId를 소품으로 가져야하며이를 작업 작성자에게 전달할 수 있습니다.

복잡하게 들리지만 실제로는 우려의 분리에 관한 것입니다.


0

다음을 사용해 볼 수 있습니다.

redux-named-reducers

다음과 같이 코드의 어느 곳에서나 상태를 얻을 수 있습니다.

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

그러나 액션의 페이로드로 외부 상태를 전달하는 것이 더 나은지 먼저 생각하십시오.


0

다른 방법으로 react-redux를 사용하고 한 곳에서만 해당 작업이 필요하거나 HOC (Higher oder component)를 생성해도 괜찮은 경우 필요한 모든 곳에서 중요한 점은 이것이 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}

(함수는 실제로 무효가 아닌 액션 자체를 반환하지만 대부분의 경우 무시합니다).

하지만 할 수있는 일은 다음과 같습니다.

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 문서와 같은 세부 사항에서 길을 잃지 않기 때문에 문서화가 이해하기 쉽습니다.


-1

액션을 전달하는 동안 매개 변수를 전달할 수 있습니다. 이 경우 accountDetails.stateOfResidenceId액션에 전달한 다음 감속기에 페이로드로 전달할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.