web-dev-qa-db-fra.com

Accès à une partie de l'état du réducteur à partir d'un réducteur dans un autre réducteur

Je ne sais pas comment accéder à un indicateur booléen isLoading depuis le réducteur reducerForm.js Dans reducerRegister.js. J'ai utilisé combineReducers() et j'utilise isLoading pour désactiver un bouton lors de la soumission du formulaire.

Son état initial est faux, après avoir cliqué sur soumettre, il devient true. Une fois la soumission du formulaire réussie, isLoading est réinitialisé sur false. Voici le code correspondant à ce problème:

actionRegister.js

let _registerUserFailure = (payload) => {
    return {
        type: types.SAVE_USER_FAILURE,
        payload
    };
};
let _registerUserSuccess = (payload) => {
    return {
        type: types.SAVE_USER_SUCCESS,
        payload,
        is_Active: 0,
        isLoading:true
    };
};

let _hideNotification = (payload) => {
    return {
        type: types.HIDE_NOTIFICATION,
        payload: ''
    };
};

// asynchronous helpers
export function registerUser({ // use redux-thunk for asynchronous dispatch
    timezone,
    password,
    passwordConfirmation,
    email,
    name
}) {
    return dispatch => {
        axios.all([axios.post('/auth/signup', {
                    timezone,
                    password,
                    passwordConfirmation,
                    email,
                    name,
                    is_Active: 0
                })
                // axios.post('/send', {email})
            ])
            .then(axios.spread(res => {
                dispatch(_registerUserSuccess(res.data.message));
                dispatch(formReset());
                setTimeout(() => {
                    dispatch(_hideNotification(res.data.message));
                }, 10000);
            }))
            .catch(res => {
                // BE validation and passport error message
                dispatch(_registerUserFailure(res.data.message));
                setTimeout(() => {
                    dispatch(_hideNotification(res.data.message));
                }, 10000);
            });
    };
} 

actionForm.js

export function formUpdate(name, value)  {
    return {
        type: types.FORM_UPDATE_VALUE,
        name, //shorthand from name:name introduced in ES2016
        value
    };
}
export function formReset() {
  return {
    type: types.FORM_RESET
  };
}

reducerRegister.js

const INITIAL_STATE = {
  error:{},
  is_Active:false,
  isLoading:false
};
const reducerSignup = (state = INITIAL_STATE , action) => {
  switch(action.type) {
    case types.SAVE_USER_SUCCESS:
      return { ...state, is_Active:false, isLoading: true, error: { register: action.payload }};
      case types.SAVE_USER_FAILURE:
      return { ...state, error: { register: action.payload }};
      case types.HIDE_NOTIFICATION:
      return { ...state , error:{} };
   }
      return state;
};
export default reducerSignup;

reducerForm.js

const INITIAL_STATE = {
    values: {}
};
const reducerUpdate = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case types.FORM_UPDATE_VALUE:
            return Object.assign({}, state, {
                values: Object.assign({}, state.values, {
                    [action.name]: action.value,
                })
            });
        case types.FORM_RESET:
        return INITIAL_STATE;
        // here I need isLoading value from reducerRegister.js
    }
    return state;
};
export default reducerUpdate;

reducerCombined.js

import { combineReducers } from 'redux';
import reducerRegister from './reducerRegister';
import reducerLogin from './reducerLogin';
import reducerForm from './reducerForm';

const rootReducer = combineReducers({
  signup:reducerRegister,
  signin: reducerLogin,
  form: reducerForm
});

export default rootReducer;

C'est là que j'utilise isLoading:

  let isLoading = this.props.isLoading;
<FormGroup>
    <Col smOffset={4} sm={8}>
     <Button type="submit"  disabled={isLoading}
       onClick={!isLoading ? isLoading : null}
     >
     { isLoading ? 'Creating...' : 'Create New Account'}
       </Button>
   </Col>
       </FormGroup>

Mappage de l'état aux accessoires dans le même composant

function mapStateToProps(state) {
    return {
        errorMessage: state.signup.error,
    isLoading: state.signup.isLoading,
    values: state.form.values

    };
}
16
Ilija Bradaš

Ceci est couvert dans le Redux FAQ at http://redux.js.org/docs/faq/Reducers.html#reducers-share-state :

De nombreux utilisateurs souhaitent par la suite essayer de partager des données entre deux réducteurs, mais constatent que combineReducers ne leur permet pas de le faire. Plusieurs approches peuvent être utilisées:

  • Si un réducteur a besoin de connaître les données d'une autre tranche d'état, la forme de l'arborescence d'état peut avoir besoin d'être réorganisée de sorte qu'un seul réducteur gère plus de données.
  • Vous devrez peut-être écrire certaines fonctions personnalisées pour gérer certaines de ces actions. Cela peut nécessiter le remplacement de combineReducers par votre propre fonction de réduction de niveau supérieur. Vous pouvez également utiliser un utilitaire tel que des réducteurs de réduction pour exécuter combineReducers pour gérer la plupart des actions, mais également exécuter un réducteur plus spécialisé pour des actions spécifiques qui traversent des tranches d'état.
  • Les créateurs d'actions asynchrones tels que redux-thunk ont ​​accès à l'état entier via getState (). Un créateur d'action peut récupérer des données supplémentaires de l'état et les mettre dans une action, de sorte que chaque réducteur dispose de suffisamment d'informations pour mettre à jour sa propre tranche d'état.
21
markerikson

Un réducteur ne peut pas accéder à l'état d'un autre réducteur, mais si vous utilisez redux-thunk vous pouvez le faire à partir d'un créateur d'action. Par exemple, vous pouvez définir un créateur d'action comme celui-ci:

export const someAction = () =>
  (dispatch, getState) => {
    const someVal = getState().someReducer.someVal;
    dispatch({ type: types.SOME_ACTION, valFromOtherReducer: someVal });
  };
13
Samo

React Redux fonctionne sur un flux de données unidirectionnel.

Action ---> Reducer /store ---> Reducer

Le réducteur fonctionne sur un petit sous-ensemble de magasin, vous ne pouvez pas accéder au magasin à l'intérieur du réducteur qui ne fait pas partie du réducteur. vous pouvez soit déclencher une nouvelle action à partir du composant en fonction du retour d'état du réducteur.

6
Khalid Azam