Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing a part of reducer state from one reducer within another reducer

I do not know how to access a boolean isLoading flag from reducerForm.js reducer in reducerRegister.js. I have used combineReducers() and I use isLoading to disable a button during form submit.

It's initial state is false, after clicking submit, it changes to true. After the form submission is successful, isLoading is reset to false again. Below is the relevant code for this issue:

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; 

This is where I use 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> 

Mapping state to props within the same component

function mapStateToProps(state) {     return {         errorMessage: state.signup.error,     isLoading: state.signup.isLoading,     values: state.form.values      }; } 
like image 453
Ilija Bradaš Avatar asked Feb 15 '17 01:02

Ilija Bradaš


People also ask

Can you call a reducer function from another reducer function within the same slice using Redux toolkit?

1 Answer. Show activity on this post. Also, reducer functions have no this , because there are no class instances involved. They're just functions.


1 Answers

This is covered in the Redux FAQ at https://redux.js.org/faq/reducers#how-do-i-share-state-between-two-reducers-do-i-have-to-use-combinereducers:

Many users later want to try to share data between two reducers, but find that combineReducers does not allow them to do so. There are several approaches that can be used:

  • If a reducer needs to know data from another slice of state, the state tree shape may need to be reorganized so that a single reducer is handling more of the data.
  • You may need to write some custom functions for handling some of these actions. This may require replacing combineReducers with your own top-level reducer function. You can also use a utility such as reduce-reducers to run combineReducers to handle most actions, but also run a more specialized reducer for specific actions that cross state slices.
  • Async action creators such as redux-thunk have access to the entire state through getState(). An action creator can retrieve additional data from the state and put it in an action, so that each reducer has enough information to update its own state slice.
like image 95
markerikson Avatar answered Oct 29 '22 16:10

markerikson