Accessing a reducer state from within another reducer
The best way to proceed is to send to Loading state reducer an information to know if the other reducer already have data. To have at the end:
const loading = (state = false, action) => {
switch (action.type) {
case 'GET_AUDIT_DATA':
if(!action.dataAlreadyInitialized){
return true
}
case 'GET_AUDIT_DATA_RECEIVED':
return false
case 'GET_AUDIT_DATA_ERROR':
return false
default:
return state
}
}
You should have access from your action function to the application state and do:
dispatch({
type:'GET_AUDIT_DATA',
dataAlreadyInitialized: appState.auditData.length > 0
});
import store from '../../../redux/store'
console.log(store.getState().loginReducer.accessToken)
Through this statement we will get state of accessToken
The accepted answer is fine (pass in the data length through the action) but can get laborious if it's a piece of information that is widely used. There is another solution that is sometimes preferable for something like 'current user' that might be used by every action.
According to the Redux FAQ https://redux.js.org/faq/reducers it is perfectly acceptable to add a third argument to the reducer function. I.e.:
Loading state reducer
const loading = (state = false, action, noData) => {
switch (action.type) {
case 'GET_AUDIT_DATA':
return noData
case 'GET_AUDIT_DATA_RECEIVED':
return false
case 'GET_AUDIT_DATA_ERROR':
return false
default:
return state
}
}
Combining reducers
Unfortunately it means we have to write code to combine the reducers, rather than use the combineReducers shortcut. But it's not too hard, you just call each reducer and create a new object if anything changed:
const allReducers = (state = null, action) => {
const auditData = AuditData(state?.auditData, action);
const auditLoading = AuditLoading(state?.auditLoading, action, !state?.auditData?.length);
const modifiedOrders = ModifiedOrders(state?.modifiedOrders, action);
return (auditData !== state?.auditData ||
auditLoading !== state?.auditLoading ||
modifiedOrders !== state?.modifiedOrders) ?
{ auditData, auditLoading, modifiedOrders } : state;
});
export default allReducers;
Notice the third argument passed to the AuditLoading reducer. No change is required to the other reducers, or to the code that invokes the action. Which is nice!
You can call getState()
over a store to get the list of reducers and the current state inside the reducers.
- Import the
store
intoauditLoading
(use store to get values. Don't mutate the store) store.getState().auditLoading
will give you the state ofauditLoading
reducer.
This approach is similar to the callback provided by redux-thunk
. In which (dispatch, getState) => {}
will be returned to the action.